home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / infoserv / gopher / mvs / gopher.ggmvs.distrib.cntl.v2r2.Z / gopher.ggmvs.distrib.cntl.v2r2
Encoding:
Text File  |  1993-08-07  |  502.5 KB  |  15,424 lines

  1. //JOBNAME JOB ACCOUNT,'NAME'
  2. //*------------------------------------------------------------------*/
  3. //*                                                                  */
  4. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993    */
  5. //*                                                                  */
  6. //* This software is provided on an "AS IS" basis. All warranties,   */
  7. //* including the implied warranties of merchantability and fitness, */
  8. //* are expressly denied.                                            */
  9. //*                                                                  */
  10. //* Provided this copyright notice is included, this software may    */
  11. //* be freely distributed and not offered for sale.                  */
  12. //*                                                                  */
  13. //* Changes or modifications may be made and used only by the maker  */
  14. //* of same, and not further distributed. Such modifications should  */
  15. //* be mailed to the author for consideration for addition to the    */
  16. //* software and incorporation in subsequent releases.               */
  17. //*                                                                  */
  18. //*------------------------------------------------------------------*/
  19. //*
  20. //*    GOPHER - MVS Gopher Client and Server
  21. //*
  22. //*  Version: 2  Release: 2
  23. //*
  24. //* Author: Steve Bacher <seb@draper.com>
  25. //*
  26. //* Date: 7 Aug 1993
  27. //*
  28. //*-------------------------------------------------------------------
  29. //*
  30. //* This job creates the distribution libraries (PDS's).
  31. //*
  32. //* Run this JCL to create the PDS's, after customizing to suit.
  33. //* (Obviously, put in a good JOB statement first.)
  34. //* To customize the JCL, change the defaults on the //MDLOAD PROC
  35. //* statement to your liking, particularly the PREFIX default.
  36. //* You might also want to change the final qualifiers of the PDS's
  37. //* created - to do this, find the // EXEC MDLOAD statements and
  38. //* change the value of the TO parameter.
  39. //*
  40. //* See the $$README file (of the CNTL PDS, first in this stream)
  41. //* for the rest of the installation instructions.
  42. //*
  43. //MDLOAD PROC CLS='*',BS='6160',U='3380',V='',
  44. //      TRK1='60',TRK2='10',DIR='35',RLSE='RLSE',
  45. //      PREFIX='GOPHER.INSTALL.'
  46. //*
  47. //IEBUPDTE EXEC PGM=IEBUPDTE,PARM=NEW
  48. //SYSPRINT DD SYSOUT=&CLS
  49. //SYSUT2 DD DISP=(NEW,CATLG,DELETE),DSN=&PREFIX.&TO,
  50. //  DCB=(RECFM=FB,LRECL=80,BLKSIZE=&BS),
  51. //  SPACE=(TRK,(&TRK1,&TRK2,&DIR),&RLSE),UNIT=&U,VOL=SER=&V
  52. //*
  53. //  PEND
  54. //*
  55. //CNTL     EXEC MDLOAD,BS='6160',TRK1='10',TRK2='1',TO='CNTL'
  56. //SYSIN    DD   DATA,DLM='?!'
  57. ./ ADD NAME=$$README
  58.  
  59. ------------------------------------------------------------------------
  60.  
  61.  Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992, 1993
  62.  
  63.  MVS Gopher Server originally by Shawn Hart (Univ. of Delaware).
  64.  
  65.  This software is provided on an "AS IS" basis.  All warranties,
  66.  including the implied warranties of merchantability and fitness,
  67.  are expressly denied.
  68.  
  69.  Provided this copyright notice is included, this software may
  70.  be freely distributed and not offered for sale.
  71.  
  72.  Changes or modifications may be made and used only by the maker
  73.  of same, and not further distributed.  Such modifications should
  74.  be mailed to the author for consideration for addition to the
  75.  software and incorporation in subsequent releases.
  76.  
  77. ------------------------------------------------------------------------
  78.  
  79.  MVS Gopher Client
  80.  
  81.  Original Author:          Steve Bacher  <seb@draper.com>
  82.  
  83.  MVS Gopher Server
  84.  
  85.  Original Author:          Shawn Hart    <shawn.hart@mvs.udel.edu>
  86.  
  87.  Various enhancements and customizations to both the client and the
  88.  server have been contributed by:
  89.  
  90.     Steve Bacher   <seb@draper.com>
  91.     Lou Joseph     <cwmy5c@irishmvs.cc.nd.edu>
  92.     Denis DeLaRoca <csp1dwd@mvs.oac.ucla.edu>
  93.     Dwight Cook    <sysdc@uokmvsa.backbone.uoknor.edu>
  94.     Rachna Agrawal <rachna@clemson.clemson.edu>
  95.  
  96. ------------------------------------------------------------------------
  97.  
  98.  Contents of PDS's belonging to Gopher distribution:
  99.  
  100.  Member     PDS Type    Description
  101.  
  102.  $$README   CNTL        This file
  103.  $CHANGES   CNTL        Changes since the last release
  104.  ACCESS     CNTL        Sample server access file
  105.  ALLOAD     CNTL        JCL to allocate GOPHER load and object libraries
  106.  COMPILE    CNTL        JCL to compile C sources for client and server
  107.  GOPHERD    CNTL        JCL to run the GOPHER server in batch (No TSO)
  108.  GOPHERT    CNTL        JCL to run the GOPHER server in batch (w. TSO)
  109.  HELP       CNTL        TSO Help for Gopher client
  110.  INSTALLC   CNTL        How to install the GOPHER MVS client
  111.  INSTALLS   CNTL        How to install the GOPHER MVS server
  112.  LINKC      CNTL        JCL to linkedit object into client load module
  113.  LINKS      CNTL        JCL to linkedit object into server load modules
  114.  MENU       CNTL        Initial Gopher server menu
  115.  PARMS      CNTL        Sample Gopher startup parameters
  116.  GOPHER     CLIST       Exec by which users invoke the Gopher client
  117.  NNMFIUCV   CLIST       Exec to check for multiple socket applications
  118.  HOSTNAME   CLIST       Sample "hostname" command for REXX feature
  119.  TSOHELP    CLIST       Sample REXX exec for Gopher TSO HELP menu hole
  120.  GGM...     PANEL       ISPF regular panels
  121.  GG...      H           C headers for compilation
  122.  GG...      C           C source for compilation
  123.  ABOUT...   ABOUT       "About This Gopher" text
  124.  
  125. --------------------------------------------------------------------
  126.  
  127. Where to Go from Here:
  128.  
  129.  To install the GOPHER MVS client, read member INSTALLC.
  130.  
  131.  To install the GOPHER MVS server, read member INSTALLS.
  132.  
  133. Note:
  134.  
  135.  You may install only the client, only the server, or both the
  136.  client and the server.  It is purely up to what your needs are.
  137.  
  138. --------------------------------------------------------------------
  139.  
  140.  Questions?  Comments?  Suggestions?  Gripes?  Please email to...
  141.  
  142.  Steve Bacher      <seb@draper.com>
  143.  
  144. ./ ADD NAME=$CHANGES
  145. Changes:
  146.  
  147.  10 Jul 93 - Version 2 Release 2
  148.  
  149.              Remote FTP Gateway
  150.              Configurable GOPHERRC: domain and telnet may be specified
  151.              Object-code-only distribution for those without C compilers
  152.              Improvements to TSO GOPHER exec for users without XPROC
  153.               or without C runtime in linklist
  154.              DD:ddname(member) works now for nested PDS member
  155.               references, making installing the ABOUT PDS simpler
  156.  
  157.  20 Mar 93 - Version 2 Release 1
  158.  
  159.              Improved browse function
  160.              Printing support
  161.              Bookmark support
  162.              New commands: PRT, INFO, MENU, BOOKMARK
  163.              Configurable startup parameter file
  164.              Ability to run multiple servers on same MVS
  165.  
  166.  07 Dec 92 - Customizations to support SNS/TCPAccess
  167.  
  168.  19 Oct 92 - Improvements in initial startup and GOPHERRC customization
  169.  
  170. ./ ADD NAME=ACCESS
  171. !
  172. ! Format of entries:
  173. !
  174. ! filename (fully qualified, all uppercase, no quotes)
  175. ! can be "DD:DDNAME" or "EXEC:EXECNAME"
  176. !
  177. ! followed by names of hosts which are authorized to access the data.
  178. ! If no host name list is present, all hosts are authorized
  179. !
  180. ! You may specify the same file name more than once, if you need
  181. ! more lines to put host names on.
  182. !
  183. ! Individual PDS members must be specified separately.  A PDS without
  184. ! a member name establishes access only to the PDS directory.
  185. !
  186. ! Note that the default directory MUST be in this table.
  187. !
  188. ! Also note that in the case of EXECs, the EXEC must live in the
  189. ! library allocated to GGEXEC in the Gopher server JCL.
  190. !
  191. ! *** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY IS FULLY
  192. ! *** ACCESSIBLE TO GOPHER REGARDLESS OF THIS TABLE!  USE THIS TABLE
  193. ! *** TO GOVERN CONTROL TO THE EXEC ITSELF!!!
  194.  
  195. !
  196. ! below is default directory spec, which MUST be in this table
  197. !
  198. DD:GGGOPHER
  199.  
  200. !
  201. ! Use the following for "About This Gopher".
  202. ! Free free to specify the name of your MVS client host(s)
  203. ! for information pertinent to MVS only.  mvs1 and mvs2 are examples.
  204. !
  205. DD:GGABOUT
  206. DD:GGABOUT(ABOUT)
  207. DD:GGABOUT(ABOUTC)                                mvs1 mvs2
  208. DD:GGABOUT(ABOUTCD)                               mvs1 mvs2
  209. DD:GGABOUT(ABOUTCF)                               mvs1 mvs2
  210. DD:GGABOUT(ABOUTCO)                               mvs1 mvs2
  211. DD:GGABOUT(ABOUTCQ)                               mvs1 mvs2
  212. DD:GGABOUT(ABOUTCS)                               mvs1 mvs2
  213. DD:GGABOUT(ABOUTCSC)                              mvs1 mvs2
  214. DD:GGABOUT(ABOUTCSL)                              mvs1 mvs2
  215. DD:GGABOUT(ABOUTCSM)                              mvs1 mvs2
  216. DD:GGABOUT(ABOUTCSR)                              mvs1 mvs2
  217. DD:GGABOUT(ABOUTCSW)                              mvs1 mvs2
  218. DD:GGABOUT(ABOUTCSX)                              mvs1 mvs2
  219. DD:GGABOUT(ABOUTCX)                               mvs1 mvs2
  220. DD:GGABOUT(ABOUTS)                                mvs1 mvs2
  221. DD:GGABOUT(ABOUTSA)                               mvs1 mvs2
  222. DD:GGABOUT(ABOUTSP)                               mvs1 mvs2
  223. DD:GGABOUT(ABOUTW)
  224. DD:GGABOUT(FAQ)
  225.  
  226. !
  227. ! Here's how to do REXX execs.  Note - no arguments, only exec names
  228. !
  229. EXEC:CHECKLST                     client1 client2 mvs
  230. EXEC:WAISDIR
  231. EXEC:WAISLIST
  232. EXEC:WAISSRCH
  233.  
  234. ANY.PUBLIC.SEQ.DS
  235. ANY.SEMI.PUBLIC.SEQ.DS            goodclient1 goodclient2
  236. ANY.SEMI.PUBLIC.SEQ.DS            goodclient3 goodclient4
  237.  
  238. ! PDS without member name provides access to directory only
  239. ! All member names must be explicitly listed to be accessible.
  240.  
  241. ANY.PUBLIC.PDS
  242. ANY.PUBLIC.PDS(MEMBER1)
  243. ANY.PUBLIC.PDS(MEMBER2)
  244. ANY.PUBLIC.PDS(MEMBER3)
  245. ANY.PUBLIC.PDS(MEMBER4)
  246.  
  247.  
  248. ANY.SEMI.PUBLIC.PDS               goodclient1 goodclient2
  249. ANY.SEMI.PUBLIC.PDS               goodclient3 goodclient4
  250. ANY.SEMI.PUBLIC.PDS(MEMBER1)      goodclient1
  251. ANY.SEMI.PUBLIC.PDS(MEMBER2)      goodclient2
  252. ANY.SEMI.PUBLIC.PDS(MEMBER3)      goodclient3
  253. ANY.SEMI.PUBLIC.PDS(MEMBER4)      goodclient4
  254.  
  255. ./ ADD NAME=ALLOAD
  256. //JOBNAME  JOB ACCOUNT,'NAME'
  257. //*                                                                  */
  258. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  259. //*                                                                  */
  260. //* This software is provided on an "AS IS" basis.  All warranties,  */
  261. //* including the implied warranties of merchantability and fitness, */
  262. //* are expressly denied.                                            */
  263. //*                                                                  */
  264. //* Provided this copyright notice is included, this software may    */
  265. //* be freely distributed and not offered for sale.                  */
  266. //*                                                                  */
  267. //* Changes or modifications may be made and used only by the maker  */
  268. //* of same, and not further distributed.  Such modifications should */
  269. //* be mailed to the author for consideration for addition to the    */
  270. //* software and incorporation in subsequent releases.               */
  271. //*                                                                  */
  272. //*
  273. //* Allocate GOPHER load and object libraries before install
  274. //*
  275. //GGALLOC PROC U='3380',V=''
  276. //*
  277. //IEFBR14  EXEC PGM=IEFBR14
  278. //ALLOCDD  DD   DISP=(NEW,CATLG,DELETE),DSN=&LIB,
  279. //         DCB=(RECFM=&RF,LRECL=&LR,BLKSIZE=&BS),
  280. //         SPACE=(&BS,(&PRI,&SEC,&DIR)),UNIT=&U,VOL=SER=&V
  281. //*
  282. //         PEND
  283. //*
  284. //* The ALLOCL step allocates the load library from which the
  285. //* executable program will be run.  If you intend to place the
  286. //* executable into an existing library, you can skip this step.
  287. //* Otherwise, the name must match the name used on the LOADLIB
  288. //* parameter of the GGLINK procedure in the COMPILE JCL.
  289. //*
  290. //* If you want separate libraries for the client and the server,
  291. //* just duplicate this step and give the LIB's different names.
  292. //*
  293. //* The ALLOCO step allocates the object library into which the
  294. //* source modules will be compiled.  This library is required
  295. //* for the compile and link steps, but is not required for run
  296. //* time execution.  However, you may wish to keep the object
  297. //* library around in case there are fixes for which you will be
  298. //* recompiling individual Gopher source modules.
  299. //*
  300. //ALLOCL   EXEC GGALLOC,PRI=50,SEC=50,DIR=35,RF=U,LR=,BS=6233,
  301. //         LIB='GOPHER.LOAD'
  302. //ALLOCO   EXEC GGALLOC,PRI=50,SEC=50,DIR=35,RF=FB,LR=80,BS=2960,
  303. //         LIB='GOPHER.INSTALL.OBJ'
  304. //*
  305. ./ ADD NAME=COMPILE
  306. //JOBNAME  JOB ACCOUNT,'NAME'
  307. //*                                                                  */
  308. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  309. //*                                                                  */
  310. //* This software is provided on an "AS IS" basis.  All warranties,  */
  311. //* including the implied warranties of merchantability and fitness, */
  312. //* are expressly denied.                                            */
  313. //*                                                                  */
  314. //* Provided this copyright notice is included, this software may    */
  315. //* be freely distributed and not offered for sale.                  */
  316. //*                                                                  */
  317. //* Changes or modifications may be made and used only by the maker  */
  318. //* of same, and not further distributed.  Such modifications should */
  319. //* be mailed to the author for consideration for addition to the    */
  320. //* software and incorporation in subsequent releases.               */
  321. //*                                                                  */
  322. //*********************************************************************
  323. //*
  324. //* Compile some or all GOPHER C/370 sources to make the SYSLIN input
  325. //* to the linkedit of the executable Gopher load module(s).
  326. //*
  327. //GGCC   PROC MEMBER=,
  328. //            SRCLIB='GOPHER.INSTALL.C',         GOPHER C source PDS
  329. //            HDRLIB='GOPHER.INSTALL.H',         GOPHER C headers PDS
  330. //            OBJLIB='GOPHER.INSTALL.OBJ',       GOPHER object library
  331. //            COMMHDR='TCPIP.COMMMAC',           C/370 TCP/IP headers
  332. //            C370HDR='SYS1.EDCHDRS',            C/370 standard headers
  333. //            SYSMSGS='SYS1.EDCMSGS',            C/370 messages file
  334. //            SYSMSGM='EDCMSGE',                 C/370 message member
  335. //            VIOUNIT=VIO,                       Temporary disk unit
  336. //            OUTCLAS='*',                          SYSOUT class
  337. //            CPARMS='SOURCE EXPMAC NOAGGR NOXREF', Compile parameters
  338. //            TEST=TEST                             TEST or NOTEST
  339. //*
  340. //CCOMP     EXEC PGM=EDCCOMP,PARM='MARGINS(1,72) &TEST &CPARMS'
  341. //SYSMSGS   DD DISP=SHR,DSN=&SYSMSGS(&SYSMSGM)
  342. //SYSIN     DD DISP=SHR,DSN=&SRCLIB(&MEMBER)
  343. //SYSLIN    DD DISP=OLD,DSN=&OBJLIB(&MEMBER)
  344. //SYSLIB    DD DISP=SHR,DSN=&COMMHDR
  345. //          DD DISP=SHR,DSN=&C370HDR
  346. //USERLIB   DD DISP=SHR,DSN=&HDRLIB
  347. //SYSPRINT  DD SYSOUT=&OUTCLAS
  348. //SYSCPRT   DD SYSOUT=&OUTCLAS
  349. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  350. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
  351. //SYSUT4    DD DSN=&&SYSUT4,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  352. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=80,BLKSIZE=3200)
  353. //SYSUT6    DD DSN=&&SYSUT6,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  354. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  355. //SYSUT7    DD DSN=&&SYSUT7,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  356. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  357. //SYSUT8    DD DSN=&&SYSUT8,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  358. //   SPACE=(32000,(30,30)),DCB=(RECFM=FB,LRECL=3200,BLKSIZE=12800)
  359. //SYSUT9    DD DSN=&&SYSUT9,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  360. //   SPACE=(32000,(30,30)),DCB=(RECFM=VB,LRECL=137,BLKSIZE=882)
  361. //SYSUT10   DD SYSOUT=&OUTCLAS
  362. //*
  363. //         PEND
  364. //*
  365. //GGCLIENT EXEC GGCC,MEMBER=GGCLIENT
  366. //GGMALLOC EXEC GGCC,MEMBER=GGMALLOC
  367. //GGMCLRTX EXEC GGCC,MEMBER=GGMCLRTX
  368. //GGMCONN  EXEC GGCC,MEMBER=GGMCONN
  369. //GGMCSO   EXEC GGCC,MEMBER=GGMCSO
  370. //GGMDBM   EXEC GGCC,MEMBER=GGMDBM
  371. //GGMDFAIL EXEC GGCC,MEMBER=GGMDFAIL
  372. //GGMDIR   EXEC GGCC,MEMBER=GGMDIR
  373. //GGMDISC  EXEC GGCC,MEMBER=GGMDISC
  374. //GGMDISPL EXEC GGCC,MEMBER=GGMDISPL
  375. //GGMDSOPT EXEC GGCC,MEMBER=GGMDSOPT
  376. //GGMDUMP  EXEC GGCC,MEMBER=GGMDUMP
  377. //GGMESRVR EXEC GGCC,MEMBER=GGMESRVR
  378. //GGMFREEM EXEC GGCC,MEMBER=GGMFREEM
  379. //GGMFTP   EXEC GGCC,MEMBER=GGMFTP
  380. //GGMGETDS EXEC GGCC,MEMBER=GGMGETDS
  381. //GGMGETM  EXEC GGCC,MEMBER=GGMGETM
  382. //GGMGOFOR EXEC GGCC,MEMBER=GGMGOFOR
  383. //GGMGSRVL EXEC GGCC,MEMBER=GGMGSRVL
  384. //GGMIERR  EXEC GGCC,MEMBER=GGMIERR
  385. //GGMIGET  EXEC GGCC,MEMBER=GGMIGET
  386. //GGMINFO  EXEC GGCC,MEMBER=GGMINFO
  387. //GGMISPF  EXEC GGCC,MEMBER=GGMISPF
  388. //GGMIVGET EXEC GGCC,MEMBER=GGMIVGET
  389. //GGMIVPUT EXEC GGCC,MEMBER=GGMIVPUT
  390. //GGMMENU  EXEC GGCC,MEMBER=GGMMENU
  391. //GGMMTFER EXEC GGCC,MEMBER=GGMMTFER
  392. //GGMOUTS  EXEC GGCC,MEMBER=GGMOUTS
  393. //GGMOUTTX EXEC GGCC,MEMBER=GGMOUTTX
  394. //GGMPMSG  EXEC GGCC,MEMBER=GGMPMSG
  395. //GGMPROC  EXEC GGCC,MEMBER=GGMPROC
  396. //GGMSOCKT EXEC GGCC,MEMBER=GGMSOCKT
  397. //GGMSOPT  EXEC GGCC,MEMBER=GGMSOPT
  398. //GGMTNET  EXEC GGCC,MEMBER=GGMTNET
  399. //GGMTSO   EXEC GGCC,MEMBER=GGMTSO
  400. //GGMTYPE  EXEC GGCC,MEMBER=GGMTYPE
  401. //GGMUNALC EXEC GGCC,MEMBER=GGMUNALC
  402. //GGMVIEW  EXEC GGCC,MEMBER=GGMVIEW
  403. //GGMVTX   EXEC GGCC,MEMBER=GGMVTX
  404. //GGMWAIS  EXEC GGCC,MEMBER=GGMWAIS
  405. //GGMWHOIS EXEC GGCC,MEMBER=GGMWHOIS
  406. //GGMXTX   EXEC GGCC,MEMBER=GGMXTX
  407. //GGSERVER EXEC GGCC,MEMBER=GGSERVER
  408. //GGSTASK  EXEC GGCC,MEMBER=GGSTASK
  409. //*
  410. ./ ADD NAME=GOPHERD
  411. //GOPHERD  PROC MODULE=GGSERVER,
  412. //         STEPLIB='GOPHER.LOAD',
  413. //         EXECLIB='GOPHER.EXEC',
  414. //         ACCESS='GOPHER.ACCESS',
  415. //         ABOUT='GOPHER.ABOUT',
  416. //         MENU='GOPHER.MENU',
  417. //         PARMS='GOPHER.PARMS',
  418. //         VIO=SYSVIO,
  419. //         STDERR='*',
  420. //         STDOUT='*',
  421. //         GPARM=
  422. //*
  423. //*********************************************************************
  424. //*                                                                   *
  425. //* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.)   *
  426. //*                                                                   *
  427. //* Straight batch (no TSO access)                                    *
  428. //*                                                                   *
  429. //*********************************************************************
  430. //*
  431. //GOPHERD  EXEC PGM=&MODULE,PARM='&GPARM'
  432. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  433. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  434. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  435. //SYSERR   DD   SYSOUT=&STDERR
  436. //SYSPRINT DD   SYSOUT=&STDOUT
  437. //SYSTSIN  DD   DUMMY
  438. //SYSIN    DD   DUMMY
  439. //GGDEBUG  DD   SYSOUT=*
  440. //GGABOUT  DD   DISP=SHR,DSN=&ABOUT
  441. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  442. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  443. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  444. ./ ADD NAME=GOPHERT
  445. //GOPHERD  PROC MODULE=GGSERVER,
  446. //         STEPLIB='GOPHER.LOAD',
  447. //         EXECLIB='GOPHER.EXEC',
  448. //         ACCESS='GOPHER.ACCESS',
  449. //         ABOUT='GOPHER.ABOUT',
  450. //         MENU='GOPHER.MENU',
  451. //         PARMS='GOPHER.PARMS',
  452. //         VIO=SYSVIO,
  453. //         STDERR='*',
  454. //         STDOUT='*',
  455. //         GPARM=
  456. //*
  457. //*********************************************************************
  458. //*                                                                   *
  459. //* GOPHER daemon, by Shawn Hart (U.Del.) and Steve Bacher (D.Lab.)   *
  460. //*                                                                   *
  461. //*********************************************************************
  462. //*
  463. //GOPHERD  EXEC PGM=IKJEFT01,DYNAMNBR=128,REGION=8M,
  464. //         PARM='&MODULE &GPARM'
  465. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  466. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  467. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  468. //SYSERR   DD   SYSOUT=&STDERR
  469. //SYSPRINT DD   SYSOUT=&STDOUT
  470. //SYSTSIN  DD   DUMMY
  471. //SYSIN    DD   DUMMY
  472. //GGDEBUG  DD   SYSOUT=*
  473. //GGABOUT  DD   DISP=SHR,DSN=&ABOUT
  474. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  475. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  476. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  477. ./ ADD NAME=HELP
  478. )F Function -
  479.  
  480.  GOPHER is a distributed document delivery service, or, more generally,
  481.  a networked information retrieval service.  It allows you to access
  482.  numerous types of data on various hosts in a transparent fashion.
  483.  GOPHER presents you with a hierarchical display of information sources
  484.  which are accessed via a client/server communications link.
  485.  
  486.  There are GOPHER clients for all common hardware platforms.  The MVS
  487.  version runs as an ISPF dialog application.
  488.  
  489.  When you use the GOPHER client, information about your use of GOPHER
  490.  is stored in a data set called GOPHERRC.  If you don't have one,
  491.  GOPHER will create it for you.
  492.  
  493.  You can save Gopher information in bookmark files.  See the
  494.  help for operand BOOKMARK for details.
  495.  
  496.  For more information on customizing your GOPHER environment, get
  497.  into Gopher and select "About This GOPHER".
  498.  
  499. )I GOPHLOC          - local GOPHER help goes in member GOPHLOC
  500.  
  501. )X Syntax -
  502.  
  503.    %GOPHER
  504.               LOCAL
  505.               BOOKMARK(datasetname)
  506.               SERVER(hostname)
  507.               PATH(pathname)
  508.               PORT(portnumber)
  509.               DESCRIPTION(text)
  510.               FORCE
  511.               DEBUG
  512.               TEST
  513.  
  514.    Required:  none
  515.  
  516. )O Operands -
  517.  
  518. ))LOCAL
  519.  
  520.               Specify LOCAL if you want to enter GOPHER in "serverless"
  521.               mode - i.e. start up with your private GOPHER menu.
  522.               Specifying LOCAL accomplishes two things:
  523.  
  524.                (1) It sets the server to "-", meaning local access.
  525.                    Therefore, you must also provide a path, either
  526.                    via the PATH operand or via a "localmenu:" spec
  527.                    in your GOPHERRC file.
  528.  
  529.                (2) It allows you to use GOPHER even if there are
  530.                    other TCP/IP socket applications active elsewhere
  531.                    in your TSO session.  However, it will not allow
  532.                    you to connect to any GOPHER servers, even if you
  533.                    have a local menu item that points to one.
  534.  
  535.               For information on how to set up GOPHER menus, get into
  536.               GOPHER and select "About This Gopher".
  537.  
  538. ))BOOKMARK(datasetname)
  539.  
  540.               The name of a data set containing Gopher bookmarks,
  541.               using normal TSO data set naming conventions.
  542.  
  543.               You can create bookmarks in GOPHER by using the "B"
  544.               selection code next to a menu item, or by using the
  545.               BOOKMARK command while browsing an entry.  GOPHER will
  546.               append an entry for the selected item to the end of
  547.               the data set that you specify when asked.
  548.  
  549.               To access this bookmark in a Gopher session, you can use
  550.               the MENU command from any Gopher menu display, or you can
  551.               start Gopher with a specific bookmark file.
  552.  
  553. ))SERVER(hostname)
  554.  
  555.               The host name (or IP address) of a Gopher server.
  556.               If this is not given, GOPHER looks in your GOPHERRC
  557.               to find what server to connect to.  If it can't find
  558.               an appropriate specification, you will have to enter
  559.               a server name on the startup panel.
  560.  
  561.               A server name of a single minus sign (-) is a special
  562.               case, signifying local (serverless) access to your
  563.               own private GOPHER data.  In this case, you must tell
  564.               GOPHER where your menu is, either via the PATH operand
  565.               or in the GOPHERRC file.
  566.  
  567. ))PATH(pathname)
  568.  
  569.               The path name to be passed to the Gopher server, or
  570.               used in local access as your initial menu.  Although
  571.               the exact interpretation of the pathname string varies
  572.               depending on the server, both the MVS server and the
  573.               local GOPHER access feature interpret the pathname
  574.               as the FULLY QUALIFIED WITHOUT QUOTES name of an MVS
  575.               data set containing a gopher menu.  For information
  576.               about the format of a gopher menu, see operand MENU.
  577.  
  578. ))PORT(portnumber)
  579.  
  580.               You should never need to specify this field unless
  581.               someone has set up a special kind of Gopher server that
  582.               requires a unique port number.  In such a case, you
  583.               would generally use this along with the SERVER operand.
  584.  
  585. ))DESCRIPTION(text)
  586.  
  587.               A text string giving the heading to be displayed for
  588.               the initial directory of Gopher goodies.  Normally
  589.               either the Gopher server or the Gopher client will
  590.               have a default value for this, or you can specify
  591.               a description of your liking in your GOPHERRC file.
  592.               You can also use this to override the description
  593.               generated when you use the BOOKMARK operand to start up.
  594.  
  595. ))FORCE
  596.  
  597.               GOPHER tries to determine if there is a TCP/IP socket
  598.               application active elsewhere in your TSO environment
  599.               before starting up, to prevent TCP/IP errors.  If it
  600.               tells you that there is another client active but in
  601.               truth there is none and you know it, you can use the
  602.               FORCE keyword to make GOPHER proceed whether it finds
  603.               this to be the case or not.
  604.  
  605.               Using the LOCAL operand is one way to avoid this entire
  606.               scenario.  However, that won't allow you to access any
  607.               Gopher servers on the network.
  608.  
  609. ))DEBUG
  610.  
  611.               Set debugging mode on.  You must preallocate a file to
  612.               ddname GGDEBUG for this to work.  This can be allocated
  613.               to the terminal or a log file.  When debug mode is on,
  614.               messages describing memory allocation and deallocation
  615.               and GOPHER queries sent are dumped to the debug file.
  616.  
  617. ))TEST
  618.  
  619.               Activate C/370 interactive test (INSPECT).  GOPHER must
  620.               have been compiled with the TEST option for this to be
  621.               effective.  Note that you can also issue the TEST command
  622.               inside GOPHER to get to INSPECT, again provided that
  623.               GOPHER was compiled with the TEST option.
  624.  
  625. ./ ADD NAME=INSTALLC
  626.  
  627.  Directions for Installing the GOPHER MVS Client
  628.  
  629.  Assuming the PDS's have been created:
  630.  
  631.  1. Customize the ALLOAD, COMPILE and LINKC JCL members to reflect your
  632.  local conventions.  Note:  If you intend to place the executable into
  633.  an existing library, you can suppress that part of the ALLOAD JCL.
  634.  The name of the data set created must match across both members.
  635.  
  636.  2. Customize the GGUSER header file as shown by the comments therein.
  637.  Note in particular the defines for your TCP/IP and your C compiler.
  638.  There are changes to the linkedit JCL that are related to these.
  639.  
  640.  3. If you are running ISPF Version 2 or earlier, edit the GOPHER panels
  641.  whose names begin "GGMP...".  These are popups, and will not work
  642.  under ISPF Version 2 unless you change the )BODY line.  Remove the
  643.  WINDOW(...) parameter from the )BODY line of each panel so that the
  644.  line just says )BODY or )BODY EXPAND(``), as the case may be.
  645.  
  646.  4. Customize the GOPHER exec to define the names of the MVS libraries
  647.  to contain the panel and load library members.  The load library must
  648.  be the one specified in the ALLOAD JCL, if you are creating it anew.
  649.  Observe the comments relating to the use of LIBDEF and ISPF APPLIDs.
  650.  
  651.  It is in the GOPHER exec that you will also customize the name of the
  652.  default Gopher server.  Note that the user's GOPHERRC file gets built
  653.  from the contents of this exec.
  654.  
  655.  You may configure the GOPHER exec to use XPROC to parse the operands
  656.  given to it by the TSO user.  If you don't have XPROC, you should get
  657.  it, because the user can take advantage of all the power of TSO CLIST
  658.  style parsing if you do.  The GOPHER exec contains some code that
  659.  emulates full TSO parsing, but it isn't as robust or flexible as true
  660.  XPROC parsing.  You can get XPROC via USC's "MVS network server" code
  661.  distribution service.  For more information about this, send an email
  662.  message to SERVICE@MVSA.USC.EDU - or SERVICE@USCMVSA, which will
  663.  normally give better results if you have a BITNET (NJE) return address.
  664.  
  665.  Note that if you install one of the REXX execs, you must also install
  666.  the NNMFIUCV exec in the same library.  This exec implements a rude
  667.  check for an existing TCP/IP socket application (e.g. another GOPHER)
  668.  in a different PIE MultiTSO session.  It prevents your users from
  669.  crashing TCP/IP, so it is highly recommended that you make use of it.
  670.  
  671.  If the C/370 runtime library is not in the link list or otherwise
  672.  available to ISPF at execution time, you may arrange for it to be
  673.  allocated via LIBDEF in the GOPHER exec by setting "crunlibs".
  674.  
  675.  Now, to install:
  676.  
  677.  5. Submit the ALLOAD JCL to allocate the load library from which the
  678.  executable program will be run, as well as the object library in which
  679.  the compiled object modules will be stored.
  680.  
  681.  6. Submit the COMPILE JCL to compile all the C sources and create the
  682.  required object modules in the object library built in the above step.
  683.  Note that this compiles all the modules for both the client and the
  684.  server.  If you are installing both, you need not repeat this step.
  685.  
  686.  7. Submit the LINKC JCL to create the executable Gopher load module
  687.  from the object modules created in the above step.  This will create
  688.  or replace the load module GGCLIENT.
  689.  
  690.  Note:  The linkedit must complete with a return code of zero.  If not,
  691.  don't use the resultant load module.  Check the libraries you specified
  692.  on the link step to see what went wrong.
  693.  
  694.  In the future, if you have to recompile individual modules, you can use
  695.  the same JCL to compile only those modules, and the link will include
  696.  the new modules in the existing executable load module.  To do this,
  697.  you must retain the object library built above.
  698.  
  699.  *********************************************************************
  700.  
  701.  IMPORTANT:  If you are running TCP/IP V2R2 or higher on MVS, you must
  702.  change the following library names in the compile and link JCL:
  703.  
  704.    TCPIP.COMMMAC   should be changed to  TCPIP.SEZACMAC
  705.    TCPIP.COMMTXT   should be changed to  TCPIP.SEZACMTX
  706.  
  707.  If you are using SNS/TCPAccess, use these library names, or
  708.  whatever names are defined at your installation:
  709.  
  710.    TCPIP.COMMMAC   should be changed to  SNSTCP.V110.H
  711.    TCPIP.COMMTXT   should be changed to  SNSTCP.V110.CILIB
  712.  
  713.  If you are using SAS/C, change CEESTART to MAIN in the linkedit
  714.  ENTRY control statement.
  715.  
  716.  *********************************************************************
  717.  
  718.  Note:  If you have defined C370V1 in the GGUSER header file, you must
  719.  also include the system linklist load library or libraries containing
  720.  ISPLINK, ISPEXEC and IKJEFF18 when linking.  Otherwise you may delete
  721.  the lines from the linkedit JCL that reference them.
  722.  
  723.  Note:  You need not include the PASCAL libraries or the AMPZMVSB
  724.  module if you are using TCP/IP Version 2 or higher, in which case
  725.  you must also define TCPIPV2 in the GGUSER headerfile.
  726.  
  727.  8. Copy all the members of the panel PDS into the ISPF panel library
  728.  specified in the GOPHER exec.
  729.  
  730.  9. Copy the help member (HELP) from the CNTL PDS into your local TSO
  731.  HELP library under the name GOPHER.  You may also create an additional
  732.  HELP member called GOPHLOC containing information local to your site,
  733.  if you wish.
  734.  
  735.  10. Create the "About This Gopher" PDS from the ABOUT PDS.  This has
  736.  all the text users should see when they select the "About This Gopher"
  737.  item from the MVS client.  It also contains all the documentation you
  738.  need about setting up the client and the server, as well as creating
  739.  menus and REXX execs for use with MVS Gopher.  You may have already
  740.  done this as part of the server install, but it should also be
  741.  available from the client in "local" (serverless) mode, so that is
  742.  why I mention it here.
  743.  
  744. --------------------------------------------------------------------
  745.  
  746.  Note:  Make sure that the C/370 run time library is available,
  747.  either in the system link list or in the ISPLLIB concatenation,
  748.  before attempting to run GOPHER.  See above under customization
  749.  of the GOPHER exec.
  750.  
  751. ./ ADD NAME=INSTALLS
  752.  
  753.  Directions for Installing the GOPHER MVS Server
  754.  
  755.  Assuming the PDS's have been created:
  756.  
  757.  1. Customize the ALLOAD, COMPILE and LINKS JCL members to reflect your
  758.  local conventions.  Note:  If you intend to place the executable into
  759.  an existing library, you can suppress that part of the ALLOAD JCL.
  760.  The name of the data set created must match across both members.
  761.  
  762.  2. Customize the GGUSER header file as shown by the comments therein.
  763.  Note in particular the defines for your TCP/IP and your C compiler.
  764.  There are changes to the linkedit JCL that are related to these.
  765.  
  766.  Now, to install:
  767.  
  768.  3. Submit the ALLOAD JCL to allocate the load library from which the
  769.  executable program will be run, as well as the object library in which
  770.  the compiled object modules will be stored.
  771.  
  772.  6. Submit the COMPILE JCL to compile all the C sources and create the
  773.  required object modules in the object library built in the above step.
  774.  Note that this compiles all the modules for both the client and the
  775.  server.  If you are installing both, you need not repeat this step.
  776.  
  777.  5. Submit the LINKS JCL to create the executable Gopher load modules
  778.  from the object modules created in the above step.  This will create
  779.  or replace the load modules GGSERVER and GGSTASK.
  780.  
  781.  Note:  The linkedit must complete with a return code of zero.  If not,
  782.  don't use the resultant load module.  Check the libraries you specified
  783.  on the link step to see what went wrong.
  784.  
  785.  In the future, if you have to recompile individual modules, you can use
  786.  the same JCL to compile only those modules, and the link will include
  787.  the new modules in the existing executable load module.  To do this,
  788.  you must retain the object library built above.
  789.  
  790.  
  791.  *********************************************************************
  792.  
  793.  IMPORTANT:  If you are running TCP/IP V2R2 or higher on MVS, you must
  794.  change the following library names in the compile and link JCL:
  795.  
  796.    TCPIP.COMMMAC   should be changed to  TCPIP.SEZACMAC
  797.    TCPIP.COMMTXT   should be changed to  TCPIP.SEZACMTX
  798.  
  799.  If you are using SNS/TCPAccess, use these library names, or
  800.  whatever names are defined at your installation:
  801.  
  802.    TCPIP.COMMMAC   should be changed to  SNSTCP.V110.H
  803.    TCPIP.COMMTXT   should be changed to  SNSTCP.V110.CILIB
  804.  
  805.  If you are using SAS/C, change CEESTART to MAIN in the linkedit
  806.  ENTRY control statement.
  807.  
  808.  *********************************************************************
  809.  
  810.  Note:  If you have defined C370V1 in the GGUSER header file, you must
  811.  also include the system linklist load library containing IKJEFF18
  812.  when linking.  Otherwise you may delete the line from the linkedit
  813.  JCL that references it.
  814.  
  815.  Note:  You need not include the PASCAL libraries or the AMPZMVSB
  816.  module if you are using TCP/IP Version 2 or higher, in which case
  817.  you must also define TCPIPV2 in the GGUSER headerfile.
  818.  
  819.  6. Create the "About This Gopher" PDS from the ABOUT PDS.  This has
  820.  all the text users should see when they select the "About This Gopher"
  821.  item from the MVS client.  It also contains all the documentation you
  822.  need about setting up the client and the server, as well as creating
  823.  menus and REXX execs for use with MVS Gopher.  You may have already
  824.  done this as part of the client install.
  825.  
  826.  Note that member MENU contains the line PATH=DD:GGABOUT(ABOUT).  This
  827.  works now (it didn't use to), so there is no need to change it as long
  828.  as you have the GGABOUT DD statement in your server JCL pointing to
  829.  your ABOUT PDS (see below).
  830.  
  831.  7. Create your Gopher access file.  See the instructions in the
  832.  "About This Gopher" PDS, member ABOUTSA, for a description of the
  833.  format.  A sample member is in member ACCESS of this CNTL PDS.
  834.  
  835.  8. Create your Gopher startup parameter file.  This is not required,
  836.  but may be used to change compiled-in defaults.  See the PARMS member
  837.  for a default.
  838.  
  839.  9. Allocate a PDS to hold Gopher REXX execs.  This is not required.
  840.  See the TSOHELP exec in the clist library of the distribution for a
  841.  sample application.
  842.  
  843.  10. Create the MVS Gopher started task JCL from either of the samples
  844.  given in GOPHERD and GOPHERT.  The GOPHERT is recommended so that you
  845.  can use REXX execs that issue TSO commands, but you may not want to
  846.  use this for security reasons.  Either way, customize liberally.
  847.  
  848.  Started task parameters:
  849.  
  850.  MODULE=GGSERVER            the Gopher server load module in STEPLIB
  851.  STEPLIB='GOPHER.LOAD'      the load library containing the above
  852.  EXECLIB='GOPHER.EXEC'      the PDS containing server REXX execs
  853.  ACCESS='GOPHER.ACCESS'     the installation access file (sequential)
  854.  ABOUT='GOPHER.ABOUT'       the PDS containing "About This Gopher" info
  855.  MENU='GOPHER.MENU'         the initial gopher menu (sequential)
  856.  PARMS='GOPHER.PARMS'       the server startup file (sequential)
  857.  GPARM=                     the server EXEC parms (e.g. -d for debug)
  858.  
  859.  Note: if you specify GPARM='-D', a GGDEBUG DD must be included.
  860.  
  861.  You are strongly recommended to create 2 started tasks:  one for
  862.  non-REXX requests with MTFTASKS set to 8, and one for REXX requests
  863.  with MTFTASKS set to 1 (because of TSO/E multitasking bugs).
  864.  Give each a different port number in the GGPARMS configuration file
  865.  allocated to it.  See sample below.
  866.  
  867.  11. Add the name of the Gopher server started task (the name as it
  868.  appears in SYS1.PROCLIB, not necessarily "GOPHER") to the MVS TCPIP
  869.  profile data set (or have your MVS TCP/IP system programmer do it).
  870.  In the examples below, let's say you've called it GOPHSRV.  Add this
  871.  in 2 places:
  872.  
  873.    (a) under AUTOLOG, so that TCP/IP will start the Gopher server
  874.        automatically (a la inetd for unix) when a client connects.
  875.        Just add the name to the list (e.g. GOPHSRV).
  876.  
  877.    (b) under PORT, so nobody can spoof the Gopher port.  The format
  878.        here is:   70 TCP GOPHSRV
  879.  
  880.  Repeat both for whatever number of Gopher server started tasks you
  881.  create (with different port numbers).
  882.  
  883. --------------------------------------------------------------------
  884.  
  885.  Note:  Make sure that the C/370 run time library is available,
  886.  either in the system link list or in the STEPLIB concatenation,
  887.  before attempting to run GOPHER.
  888.  
  889. --------------------------------------------------------------------
  890.  
  891. Following is an example of how to define two Gopher servers.
  892.  
  893. 'SYS1.PROCLIB(GOPHSRV)' - the primary gopher server (port 70)
  894.                           will not run any REXX execs
  895.  
  896. //GOPHERD  PROC MODULE=GGSERVER,
  897. //         STEPLIB='GOPHER.LOAD',
  898. //         ACCESS='GOPHER.ACCESS(ACCESS)',
  899. //         PARMS='GOPHER.ACCESS(PARMS)',
  900. //         MENU='GOPHER.ACCESS(MENU)',
  901. //         STDERR='*',
  902. //         STDOUT='*',
  903. //         GPARM=
  904. //*
  905. //GOPHERD  EXEC PGM=&MODULE,PARM='&GPARM'
  906. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  907. //SYSERR   DD   SYSOUT=&STDERR
  908. //SYSPRINT DD   SYSOUT=&STDOUT
  909. //SYSIN    DD   DUMMY
  910. //GGDEBUG  DD   SYSOUT=*
  911. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  912. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  913. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  914.  
  915. 'SYS1.PROCLIB(GOPHSRV2)' - the secondary gopher server (port 1570)
  916.                            will run REXX execs
  917.  
  918. //GOPHERD2 PROC MODULE=GGSERVER,
  919. //         STEPLIB='GOPHER.LOAD',
  920. //         EXECLIB='GOPHER.EXEC',
  921. //         ACCESS='GOPHER.ACCESS(ACCESS2)',
  922. //         PARMS='GOPHER.ACCESS(PARMS2)',
  923. //         MENU='GOPHER.ACCESS(MENU2)',
  924. //         VIO=VIO,
  925. //         STDERR='*',
  926. //         STDOUT='*',
  927. //         GPARM=
  928. //*
  929. //GOPHERD2 EXEC PGM=IKJEFT01,DYNAMNBR=128, PARM='&MODULE &GPARM'
  930. //STEPLIB  DD   DISP=SHR,DSN=&STEPLIB
  931. //SYSEXEC  DD   DISP=SHR,DSN=&EXECLIB  /* needed for %-invoked execs */
  932. //GGEXEC   DD   DISP=SHR,DSN=&EXECLIB
  933. //SYSTSPRT DD   UNIT=&VIO,SPACE=(TRK,(100,100)),RECFM=VBA,LRECL=255
  934. //SYSERR   DD   SYSOUT=&STDERR
  935. //SYSPRINT DD   SYSOUT=&STDOUT
  936. //SYSTSIN  DD   DUMMY
  937. //SYSIN    DD   DUMMY
  938. //GGDEBUG  DD   SYSOUT=*
  939. //GGACCESS DD   DISP=SHR,DSN=&ACCESS
  940. //GGPARMS  DD   DISP=SHR,DSN=&PARMS
  941. //GGGOPHER DD   DISP=SHR,DSN=&MENU
  942.  
  943. 'GOPHER.ACCESS(PARMS)' - startup parameters used by the primary server
  944.  
  945. mtftasks  8    (this is the default)
  946. port      70   (this is the default too)
  947.  
  948. 'GOPHER.ACCESS(PARMS2)'- startup parameters used by the secondary server
  949.  
  950. mtftasks  1       Force single threading to prevent TSO burpages
  951. port      1570    Must be different from primary server's port
  952.  
  953. -----------------------------------------------------------------------
  954.  
  955. I have not included members ACCESS, ACCESS2, MENU and MENU2, but you
  956. will find samples elsewhere in this distribution.  ACCESS and ACCESS2
  957. can be the same, except that you don't need the REXX execs to be in
  958. ACCESS since ACCESS can't run REXX execs.  MENU and MENU2 should be
  959. the same, since you may want to configure various Gopher clients
  960. on other machines to try both MVS servers, but it's up to you.
  961.  
  962. ./ ADD NAME=LINKC
  963. //JOBNAME  JOB ACCOUNT,'NAME'
  964. //*                                                                  */
  965. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  966. //*                                                                  */
  967. //* This software is provided on an "AS IS" basis.  All warranties,  */
  968. //* including the implied warranties of merchantability and fitness, */
  969. //* are expressly denied.                                            */
  970. //*                                                                  */
  971. //* Provided this copyright notice is included, this software may    */
  972. //* be freely distributed and not offered for sale.                  */
  973. //*                                                                  */
  974. //* Changes or modifications may be made and used only by the maker  */
  975. //* of same, and not further distributed.  Such modifications should */
  976. //* be mailed to the author for consideration for addition to the    */
  977. //* software and incorporation in subsequent releases.               */
  978. //*                                                                  */
  979. //*********************************************************************
  980. //*
  981. //* Linkedit an executable Gopher load module.
  982. //*
  983. //GGLINK PROC LOADLIB='GOPHER.LOAD',             Executable load library
  984. //            OBJLIB='GOPHER.INSTALL.OBJ',       Input object PDS
  985. //            PLIBASE='SYS1.PLIBASE',            PL/1   link library
  986. //            EDCBASE='SYS1.SEDCBASE',           C/370  link library
  987. //            IBMBASE='SYS1.SIBMBASE',           PL/1+C common library
  988. //            COMMTXT='TCPIP.COMMTXT',           TCP/IP link library
  989. //            VIOUNIT=VIO,                       Temporary disk unit
  990. //            OUTCLAS='*',                          SYSOUT class
  991. //            LPARMS='LIST,LET,MAP',                Linkedit parameters
  992. //            TEST=TEST                             TEST or NOTEST
  993. //*
  994. //LKED      EXEC PGM=IEWL,PARM='AMODE(31),&TEST,&LPARMS'
  995. //SYSPRINT  DD SYSOUT=&OUTCLAS
  996. //SYSLIB    DD DISP=SHR,DSN=&PLIBASE
  997. //          DD DISP=SHR,DSN=&EDCBASE
  998. //          DD DISP=SHR,DSN=&IBMBASE
  999. //          DD DISP=SHR,DSN=&COMMTXT
  1000. //SYSLMOD   DD DISP=SHR,DSN=&LOADLIB
  1001. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  1002. //          SPACE=(32000,(30,30))
  1003. //*
  1004. //         PEND
  1005. //*
  1006. //*
  1007. //* Link GOPHER load module. Like SMP/E, expect return code 8 when
  1008. //* doing this from scratch.  Additional one-or-two-module links
  1009. //* will just replace the corresponding parts of the load module.
  1010. //*
  1011. //GGLINK EXEC GGLINK
  1012. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGCLIENT)
  1013. //            DD DISP=SHR,DSN=&OBJLIB(GGMALLOC)
  1014. //            DD DISP=SHR,DSN=&OBJLIB(GGMCLRTX)
  1015. //            DD DISP=SHR,DSN=&OBJLIB(GGMCONN)
  1016. //            DD DISP=SHR,DSN=&OBJLIB(GGMCSO)
  1017. //            DD DISP=SHR,DSN=&OBJLIB(GGMDBM)
  1018. //            DD DISP=SHR,DSN=&OBJLIB(GGMDFAIL)
  1019. //            DD DISP=SHR,DSN=&OBJLIB(GGMDIR)
  1020. //            DD DISP=SHR,DSN=&OBJLIB(GGMDISC)
  1021. //            DD DISP=SHR,DSN=&OBJLIB(GGMDISPL)
  1022. //            DD DISP=SHR,DSN=&OBJLIB(GGMDSOPT)
  1023. //            DD DISP=SHR,DSN=&OBJLIB(GGMDUMP)
  1024. //            DD DISP=SHR,DSN=&OBJLIB(GGMESRVR)
  1025. //            DD DISP=SHR,DSN=&OBJLIB(GGMFREEM)
  1026. //            DD DISP=SHR,DSN=&OBJLIB(GGMFTP)
  1027. //            DD DISP=SHR,DSN=&OBJLIB(GGMGETDS)
  1028. //            DD DISP=SHR,DSN=&OBJLIB(GGMGETM)
  1029. //            DD DISP=SHR,DSN=&OBJLIB(GGMGOFOR)
  1030. //            DD DISP=SHR,DSN=&OBJLIB(GGMGSRVL)
  1031. //            DD DISP=SHR,DSN=&OBJLIB(GGMIERR)
  1032. //            DD DISP=SHR,DSN=&OBJLIB(GGMIGET)
  1033. //            DD DISP=SHR,DSN=&OBJLIB(GGMINFO)
  1034. //            DD DISP=SHR,DSN=&OBJLIB(GGMISPF)
  1035. //            DD DISP=SHR,DSN=&OBJLIB(GGMIVGET)
  1036. //            DD DISP=SHR,DSN=&OBJLIB(GGMIVPUT)
  1037. //            DD DISP=SHR,DSN=&OBJLIB(GGMMENU)
  1038. //            DD DISP=SHR,DSN=&OBJLIB(GGMMTFER)
  1039. //            DD DISP=SHR,DSN=&OBJLIB(GGMOUTS)
  1040. //            DD DISP=SHR,DSN=&OBJLIB(GGMOUTTX)
  1041. //            DD DISP=SHR,DSN=&OBJLIB(GGMPMSG)
  1042. //            DD DISP=SHR,DSN=&OBJLIB(GGMPROC)
  1043. //            DD DISP=SHR,DSN=&OBJLIB(GGMSOCKT)
  1044. //            DD DISP=SHR,DSN=&OBJLIB(GGMSOPT)
  1045. //            DD DISP=SHR,DSN=&OBJLIB(GGMTNET)
  1046. //            DD DISP=SHR,DSN=&OBJLIB(GGMTSO)
  1047. //            DD DISP=SHR,DSN=&OBJLIB(GGMTYPE)
  1048. //            DD DISP=SHR,DSN=&OBJLIB(GGMUNALC)
  1049. //            DD DISP=SHR,DSN=&OBJLIB(GGMVIEW)
  1050. //            DD DISP=SHR,DSN=&OBJLIB(GGMVTX)
  1051. //            DD DISP=SHR,DSN=&OBJLIB(GGMWAIS)
  1052. //            DD DISP=SHR,DSN=&OBJLIB(GGMWHOIS)
  1053. //            DD DISP=SHR,DSN=&OBJLIB(GGMXTX)
  1054. //            DD *
  1055.  ENTRY   CEESTART
  1056.  NAME    GGCLIENT(R)
  1057. /*
  1058. ./ ADD NAME=LINKS
  1059. //JOBNAME  JOB ACCOUNT,'NAME'
  1060. //*                                                                  */
  1061. //* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  1062. //*                                                                  */
  1063. //* This software is provided on an "AS IS" basis.  All warranties,  */
  1064. //* including the implied warranties of merchantability and fitness, */
  1065. //* are expressly denied.                                            */
  1066. //*                                                                  */
  1067. //* Provided this copyright notice is included, this software may    */
  1068. //* be freely distributed and not offered for sale.                  */
  1069. //*                                                                  */
  1070. //* Changes or modifications may be made and used only by the maker  */
  1071. //* of same, and not further distributed.  Such modifications should */
  1072. //* be mailed to the author for consideration for addition to the    */
  1073. //* software and incorporation in subsequent releases.               */
  1074. //*                                                                  */
  1075. //*********************************************************************
  1076. //*
  1077. //* Linkedit an executable Gopher load module.
  1078. //*
  1079. //GGLINK PROC LOADLIB='GOPHER.LOAD',             Executable load library
  1080. //            OBJLIB='GOPHER.INSTALL.OBJ',       Input object PDS
  1081. //            PLIBASE='SYS1.PLIBASE',            PL/1   link library
  1082. //            EDCBASE='SYS1.SEDCBASE',           C/370  link library
  1083. //            IBMBASE='SYS1.SIBMBASE',           PL/1+C common library
  1084. //            COMMTXT='TCPIP.COMMTXT',           TCP/IP link library
  1085. //            VIOUNIT=VIO,                       Temporary disk unit
  1086. //            OUTCLAS='*',                          SYSOUT class
  1087. //            LPARMS='LIST,LET,MAP',                Linkedit parameters
  1088. //            TEST=TEST                             TEST or NOTEST
  1089. //*
  1090. //LKED      EXEC PGM=IEWL,PARM='AMODE(31),&TEST,&LPARMS'
  1091. //SYSPRINT  DD SYSOUT=&OUTCLAS
  1092. //SYSLIB    DD DISP=SHR,DSN=&PLIBASE
  1093. //          DD DISP=SHR,DSN=&EDCBASE
  1094. //          DD DISP=SHR,DSN=&IBMBASE
  1095. //          DD DISP=SHR,DSN=&COMMTXT
  1096. //SYSLMOD   DD DISP=SHR,DSN=&LOADLIB
  1097. //SYSUT1    DD DSN=&&SYSUT1,UNIT=&VIOUNIT,DISP=(NEW,DELETE),
  1098. //          SPACE=(32000,(30,30))
  1099. //*
  1100. //         PEND
  1101. //*
  1102. //* Link GOPHER server subtask module.
  1103. //*
  1104. //GGLINK EXEC GGLINK
  1105. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGSTASK)
  1106. //            DD DISP=SHR,DSN=&OBJLIB(GGMALLOC)
  1107. //            DD DISP=SHR,DSN=&OBJLIB(GGMDFAIL)
  1108. //            DD DISP=SHR,DSN=&OBJLIB(GGMDUMP)
  1109. //            DD DISP=SHR,DSN=&OBJLIB(GGMFTP)
  1110. //            DD DISP=SHR,DSN=&OBJLIB(GGMGSRVL)
  1111. //            DD DISP=SHR,DSN=&OBJLIB(GGMIERR)
  1112. //            DD DISP=SHR,DSN=&OBJLIB(GGMISPF)
  1113. //            DD DISP=SHR,DSN=&OBJLIB(GGMIVPUT)
  1114. //            DD DISP=SHR,DSN=&OBJLIB(GGMOUTS)
  1115. //            DD DISP=SHR,DSN=&OBJLIB(GGMPMSG)
  1116. //            DD DISP=SHR,DSN=&OBJLIB(GGMPROC)
  1117. //            DD DISP=SHR,DSN=&OBJLIB(GGMSOCKT)
  1118. //            DD DISP=SHR,DSN=&OBJLIB(GGMTSO)
  1119. //            DD DISP=SHR,DSN=&OBJLIB(GGMUNALC)
  1120. //            DD *
  1121.  INCLUDE SYSLIB(IUCVFORC)
  1122.  INCLUDE SYSLIB(EDCMTFS)
  1123.  ENTRY   CEESTART
  1124.  NAME    GGSTASK(R)
  1125. /*
  1126. //*
  1127. //* Link GOPHER server main module.
  1128. //*
  1129. //GGLINKS EXEC GGLINK
  1130. //LKED.SYSLIN DD DISP=SHR,DSN=&OBJLIB(GGMMTFER)
  1131. //            DD DISP=SHR,DSN=&OBJLIB(GGSERVER)
  1132. //            DD *
  1133.  ENTRY   CEESTART
  1134.  NAME    GGSERVER(R)
  1135. /*
  1136. ./ ADD NAME=MENU
  1137. gopher_menu
  1138.  
  1139. TYPE=FILE
  1140. NAME=About This Gopher
  1141. PATH=DD:GGABOUT(ABOUT)
  1142. HOST=+
  1143. END
  1144.  
  1145. TYPE=FILE
  1146. NAME=TSO HELP (Sample Illustrating the REXX Interface)
  1147. PATH=EXEC:TSOHELP
  1148. HOST=+
  1149. END
  1150.  
  1151. TYPE=DIRECTORY
  1152. NAME=Library/Information Services
  1153. PATH=SYS0008.GOPHER.LIBRARY(LIBRS)
  1154. HOST=MVS.UDEL.EDU
  1155. END
  1156.  
  1157. TYPE=TELNET
  1158. NAME=UDINFO - University of Delaware Information
  1159. HOST=UDINFO.UDEL.EDU
  1160. END
  1161.  
  1162. TYPE=DIRECTORY
  1163. NAME=Network and System Services Computer Systems
  1164. PATH=SYS0008.GOPHER.DIR(UDTELNET)
  1165. HOST=MVS.UDEL.EDU
  1166. END
  1167.  
  1168. TYPE=DIRECTORY
  1169. NAME=Weather Across the Country
  1170. PATH=1/Weather
  1171. HOST=mermaid.micro.umn.edu
  1172. PORT=150
  1173. END
  1174.  
  1175. TYPE=DIRECTORY
  1176. NAME=Other Gopher and Information Servers
  1177. PATH=1/Other Gopher and Information Servers
  1178. HOST=gopher.micro.umn.edu
  1179. END
  1180.  
  1181. TYPE=DIRECTORY
  1182. NAME=How to use BITNET LISTSERV Servers
  1183. PATH=SYS0008.GOPHER.DIR(LISTSERV)
  1184. HOST=MVS.UDEL.EDU
  1185. END
  1186.  
  1187. TYPE=DIRECTORY
  1188. NAME=University of Delaware Newspapers
  1189. PATH=SYS0008.GOPHER.DIR(PAPERS)
  1190. HOST=MVS.UDEL.EDU
  1191. END
  1192.  
  1193. /*
  1194. ./ ADD NAME=PARMS
  1195. !
  1196. ! MVS Gopher Sample Startup Parameter File
  1197. !
  1198. ! All entries in this file have the format:   variable value comments
  1199. !
  1200. ! These are the possible values and their default settings:
  1201. !
  1202. ! mtftasks 1    Number of concurrent subtasks to handle client requests
  1203. ! port     70   The TCP port number by which clients connect
  1204. ! qlength  20   Queue length for TCP server listen function
  1205. ! timeout  60   Connection timeout specified when socket is closed
  1206. ! domain   .DRAPER.COM     The suffix to be appende to bald host names
  1207.  
  1208. mtftasks 1    Number of concurrent subtasks to handle client requests
  1209. port     70   The TCP port number by which clients connect
  1210. qlength  20   Queue length for TCP subtask creation
  1211. timeout  60   Connection timeout specified when socket is closed
  1212.  
  1213. ./ ENDUP
  1214. ?!
  1215. //ABOUT    EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='ABOUT'
  1216. //SYSIN    DD   DATA,DLM='?!'
  1217. ./ ADD NAME=ABOUT
  1218. gopher_menu
  1219.  
  1220. TYPE=FILE
  1221. NAME=What Is Gopher?
  1222. PATH=(ABOUTW)
  1223. HOST=+
  1224. END
  1225.  
  1226. TYPE=FILE
  1227. NAME=Gopher FAQ (Frequently Asked Questions) List
  1228. PATH=(FAQ)
  1229. HOST=+
  1230. END
  1231.  
  1232. TYPE=DIRECTORY
  1233. NAME=Using The Gopher MVS Client
  1234. PATH=(ABOUTC)
  1235. HOST=+
  1236. END
  1237.  
  1238. TYPE=DIRECTORY
  1239. NAME=Administering the Gopher MVS Server
  1240. PATH=(ABOUTS)
  1241. HOST=+
  1242. END
  1243.  
  1244.  
  1245. ./ ADD NAME=ABOUTC
  1246. gopher_menu
  1247.  
  1248. TYPE=FILE
  1249. NAME=Overview - Using Gopher on MVS
  1250. PATH=(ABOUTCO)
  1251. HOST=+
  1252. END
  1253.  
  1254. TYPE=FILE
  1255. NAME=Directory Mode - Viewing a Gopher Directory
  1256. PATH=(ABOUTCD)
  1257. HOST=+
  1258. END
  1259.  
  1260. TYPE=FILE
  1261. NAME=File Mode - Browsing a Gopher File
  1262. PATH=(ABOUTCF)
  1263. HOST=+
  1264. END
  1265.  
  1266. TYPE=FILE
  1267. NAME=Index Mode - Executing a Gopher Query
  1268. PATH=(ABOUTCQ)
  1269. HOST=+
  1270. END
  1271.  
  1272. TYPE=DIRECTORY
  1273. NAME=Customizing Your Gopher Startup
  1274. PATH=(ABOUTCS)
  1275. HOST=+
  1276. END
  1277.  
  1278.  
  1279. ./ ADD NAME=ABOUTCD
  1280. Directory Mode - Viewing a Gopher Directory
  1281.  
  1282. When you are viewing a Gopher directory, you may perform any of the
  1283. following actions:
  1284.  
  1285.  * Scroll up and down via the normal ISPF UP and DOWN commands or PFK's
  1286.  
  1287.  * Type one of the following letters to the left of a menu item:
  1288.  
  1289.    S - Select the item for viewing or processing
  1290.    E - Extract the contents of the item to a file
  1291.    P - Print the contents of the item to a system printer
  1292.    B - Save the entry as a bookmark (in a bookmark file)
  1293.    D - Delete this entry from the bookmark file *** not yet supported **
  1294.    Q - Display the item as a file, even if it isn't ("Query")
  1295.    I - Display the internal Information of the menu item
  1296.  
  1297.  * Enter one of the following commands on the command line:
  1298.  
  1299.    MENU - load a data set containing Gopher menu entries (e.g. bookmark)
  1300.    OPTions - set client processing options
  1301.    QUIT - exit Gopher entirely
  1302.  
  1303.    or any standard ISPF command.
  1304.  
  1305. Note:  Currently, in order to use the E or P selection code, you must
  1306.        choose the item via S or Q first.
  1307.  
  1308. When you select an item, what happens next depends on the type of the
  1309. item you have selected.
  1310.  
  1311. For a File type, you are placed in browse mode on the data.
  1312.  
  1313. For a Directory type, you get another Gopher directory.
  1314.  
  1315. For an Index type, you see a panel asking you to enter a search string
  1316. of some kind, after which a Gopher directory of results appears.
  1317.  
  1318. For a TELNET type, a telnet session is started, for which you must
  1319. enter a login name at the appropriate time.
  1320.  
  1321. For a TN3270 type, a tn3270 session is started, for which you must
  1322. enter a login name at the appropriate time.
  1323.  
  1324. For a CSO type, you are placed in a phonebook lookup session.
  1325.  
  1326. ./ ADD NAME=ABOUTCF
  1327. Browse Mode - Viewing a File in Gopher
  1328.  
  1329. When you are viewing a Gopher file, you are placed in "browse mode".
  1330. This is very similar to normal ISPF data set browse, except that:
  1331.  
  1332.  * In addition to most browse commands, you may issue any of the
  1333.    following commands:
  1334.  
  1335.    EXT or EXTRACT   - copy the current contents to a file
  1336.    PRT or PRNT      - print the current data to SYSOUT.
  1337.    BOOK or BOOKMARK - Save the entry as a bookmark (in a bookmark file).
  1338.    INFO             - Display the internal Information for this item
  1339.    OPTions          - Set Gopher client processing options
  1340.    QUIT - terminates Gopher entirely.
  1341.  
  1342.    Note that PRT is different from PRINT, which is a built-in ISPF
  1343.    command that prints the current physical screen image.
  1344.  
  1345.  * The following ISPF browse commands are the only ones that are
  1346.    ***not*** supported under GOPHER:
  1347.  
  1348.   HEX
  1349.   BROWSE
  1350.   SUBMIT
  1351.   LOCATE .label
  1352.   .<string> (to assign a label)
  1353.   FIND P'generic-string'
  1354.   DISPLAY CC/NOCC
  1355.  
  1356. ./ ADD NAME=ABOUTCO
  1357. The following is modified from Allan Tuchman's XGOPHER help.
  1358.  
  1359. Gopher on MVS is an ISPF dialog interface to the Gopher
  1360. information delivery system from the University of Minnesota.
  1361.  
  1362. The initial panel asks you to specify the name of the Gopher server
  1363. host.  Normally you leave the other input fields alone.
  1364.  
  1365. You may also specify a hostname of "-", which means that you want
  1366. to use your own private Gopher data without going through a server.
  1367. When you do this, you must provide the path name to your private
  1368. top-level menu (data set name, FULLY QUALIFIED, WITHOUT QUOTES).
  1369.  
  1370. Assuming that the top-level path points to a valid Gopher menu,
  1371. the initial display will show the top level directory of
  1372. gopher information available.  Selecting an item from this
  1373. list will fetch the contents of a file, subdirectory, or
  1374. other information.  The directory display may be updated to
  1375. show the new subdirectory.
  1376.  
  1377. To select an item, type "S" in front of it and press ENTER.
  1378. This puts you into ISPF BROWSE mode on the text of the item.
  1379. You may also type "Q" in front of an item to see it in text format
  1380. even if it is a directory.  If you have retrieved an item, you may
  1381. type "E" in front of it to extract it into a file - but you may
  1382. do this more easily via the EXTract command from within BROWSE.
  1383.  
  1384. Type "I" in front of the item to view the internal menu information.
  1385. This is sometimes helpful if you are not sure why you are having
  1386. trouble accessing an item.
  1387.  
  1388. Type "B" in front of the item to save it in a bookmark file.  You will
  1389. be prompted to supply the name of a bookmark data set; the default is
  1390. GOPHER.BOOKMARK under your TSO prefix.  You may retrieve bookmarks at a
  1391. later date by typing "MENU GOPHER.BOOKMARK" - or whatever data set name
  1392. you used - or you can put a pointer to the bookmark data set in your
  1393. private Gopher menu (for which you need to learn how to hack your
  1394. GOPHERRC file).
  1395.  
  1396. Some gopher file types are not supported by the current client.
  1397. These will not appear on your menus.  Furthermore, you may not
  1398. be permitted to access some items, depending upon the server
  1399. and the host from which you are trying to access them.  These
  1400. restrictions do not apply to local mode, where you can access
  1401. anything that you have local permission to read.
  1402.  
  1403. The Gopher MVS client is written by Steve Bacher at Draper Laboratory
  1404. (copyright 1992).
  1405.  
  1406. ./ ADD NAME=ABOUTCQ
  1407. Index Mode - Executing a Gopher Query
  1408.  
  1409. When you select a Gopher "index" or "query" option, you are expected
  1410. to enter some sort of search string.  A typical application is a
  1411. phone book lookup, or a keyword search of some archive.
  1412.  
  1413. You will see a popup panel (or just a plain panel if you are running
  1414. an old version of ISPF) that asks you to enter a search string.  Just
  1415. type it in and press ENTER.  What format the string needs to be in
  1416. depends totally on the service that is going to process it.
  1417.  
  1418. What you get back is a directory with a list of "hits" or whatever
  1419. is appropriate for the data you requested.  This is just like any
  1420. other Gopher directory.
  1421.  
  1422. With the original Gopher protocol, there was no mechanism for
  1423. defining an index/query that returned file data immediately.
  1424. MVS Gopher supports an experimental "whois" type that does this.
  1425. However, since it was only spottily implemented by other Gophers,
  1426. and not always the right way (in the humble opinion of the author
  1427. or the MVS client), it is not likely that you will see such an option
  1428. on your Gopher screen.
  1429.  
  1430. ./ ADD NAME=ABOUTCS
  1431. gopher_menu
  1432.  
  1433. Type=FILE
  1434. Name=Customizing Your Gopher Startup
  1435. Path=(ABOUTCSC)
  1436. Host=+
  1437. End
  1438.  
  1439. Type=FILE
  1440. Name=What Happens When You Start Up Gopher
  1441. Path=(ABOUTCSW)
  1442. Host=+
  1443. End
  1444.  
  1445. Type=FILE
  1446. Name=Requesting Local (Serverless) Access
  1447. Path=(ABOUTCSL)
  1448. Host=+
  1449. End
  1450.  
  1451. Type=FILE
  1452. Name=The GOPHERRC File
  1453. Path=(ABOUTCSR)
  1454. Host=+
  1455. End
  1456.  
  1457. Type=FILE
  1458. Name=Defining GOPHER Menus
  1459. Path=(ABOUTCSM)
  1460. Host=+
  1461. End
  1462.  
  1463. Type=FILE
  1464. Name=REXX Exec Interface
  1465. Path=(ABOUTCSX)
  1466. Host=+
  1467. End
  1468.  
  1469. ./ ADD NAME=ABOUTCSC
  1470.  
  1471. =======================================================================
  1472.  
  1473.  Customizing Your Gopher Startup
  1474.  
  1475. =======================================================================
  1476.  
  1477.  When you use the GOPHER client, information about your use of GOPHER
  1478.  is stored in a data set called GOPHERRC.  If you don't have one,
  1479.  GOPHER will create it for you.
  1480.  
  1481.  Your default startup menu will contain a single item pointing to a
  1482.  GOPHER server on your MVS system, whether such a server is available
  1483.  or not.  However, you can ask GOPHER to display a different startup
  1484.  menu for you.  This startup menu may have entries for the GOPHER
  1485.  server on the MVS system and one for your own private (local) data,
  1486.  which the GOPHER client accesses without querying a server.
  1487.  
  1488.  To get GOPHER to set up a different startup menu, you must edit the
  1489.  GOPHERRC file.  Note that you may set up the GOPHER startup menu to
  1490.  include a pointer to your local data - but you have to create that
  1491.  local data in order to use it.
  1492.  
  1493.  Editing the GOPHERRC file should be easy.  Just follow the
  1494.  instructions in the comments of the file itself.  For information
  1495.  about the contents of GOPHERRC, see "The GOPHERRC File."
  1496.  
  1497. ./ ADD NAME=ABOUTCSL
  1498.  
  1499. =======================================================================
  1500.  
  1501.  Requesting Local (Serverless) Access
  1502.  
  1503. =======================================================================
  1504.  
  1505.  The LOCAL operand on the GOPHER command is a convenient way of
  1506.  requesting "local" serverless mode.  Specify LOCAL on the GOPHER
  1507.  command if you want to enter GOPHER in "serverless" mode - i.e.
  1508.  start up with your private GOPHER menu.  Specifying LOCAL
  1509.  accomplishes two things:
  1510.  
  1511.   (1) It sets the server to "-", meaning local access.  Therefore, you
  1512.       must also provide a path, either via the PATH operand on the
  1513.       GOPHER command or via a "localmenu:" spec in your GOPHERRC file,
  1514.       so that GOPHER knows where to look for your private data.  The
  1515.       path is a data set name, FULLY QUALIFIED WITHOUT QUOTES.
  1516.  
  1517.   (2) It allows you to use GOPHER even if there are other TCP/IP socket
  1518.       applications active elsewhere in your TSO session.  However, it
  1519.       will not allow you to connect to any GOPHER servers, even if you
  1520.       have a local menu item that points to one.
  1521.  
  1522.  If you do not specify a server and there is no specification in
  1523.  your GOPHERRC file for one, then GOPHER will display a startup
  1524.  ISPF panel asking you to specify a server name and, optionally,
  1525.  a path name.  (Don't touch the port number!)
  1526. ./ ADD NAME=ABOUTCSM
  1527.  
  1528. =======================================================================
  1529.  
  1530.  Defining Gopher Menus
  1531.  
  1532. =======================================================================
  1533.  
  1534.  This is a description of how to define GOPHER menus that can be used
  1535.  either for your own private data or by the GOPHER server administrator
  1536.  on MVS to define publicly accessible data.
  1537.  
  1538.  Bear in mind that the menu may be used to specify data meaningful to
  1539.  a server other than MVS.  Therefore, the descriptions here should be
  1540.  interpreted in two ways:
  1541.  
  1542.  (1) how to define MVS-resident information resources
  1543.  
  1544.  (2) how to request information resources from other GOPHER servers
  1545.  
  1546. ------------------------------------------------------------------------
  1547.  
  1548.  How To Define MVS-Resident Information Resources
  1549.  
  1550.  The Gopher server (and the Gopher client, in "local" mode) determines
  1551.  how to return information to the client via menus.  These menus are
  1552.  plain MVS data sets with a particular structure.
  1553.  
  1554.  An MVS gopher menu is a sequential data set or PDS member with the
  1555.  following format:
  1556.  
  1557.  * the first line contains the string GOPHER_MENU
  1558.    (in upper, lower or mixed case)
  1559.  
  1560.  * the rest of the file contains blocks of information like this:
  1561.  
  1562.    TYPE=type
  1563.    NAME=name
  1564.    PATH=path
  1565.    HOST=host
  1566.    PORT=port
  1567.    END
  1568.  
  1569.    For compatibility with earlier versions of the MVS Gopher server,
  1570.    the following are also accepted:
  1571.  
  1572.    DISPLAY=      is equivalent to NAME=
  1573.    SELECTOR=     is equivalent to PATH=
  1574.  
  1575.    Explanations
  1576.  
  1577.    TYPE=type
  1578.  
  1579.    The type of Gopher entity (FILE, DIRECTORY, INDEX, etc.).
  1580.    In other words, one of the following:
  1581.  
  1582.    FILE      - the item is an MVS data set with text to be displayed.
  1583.                The path name is the file name or a REXX exec spec.
  1584.    DIRECTORY - the item is another Gopher directory.
  1585.                The path name is the file name or a REXX exec spec.
  1586.    INDEX     - the item is a full text search item, which means that
  1587.                the client will query the user for a search string
  1588.                which will be passed to the server along with the
  1589.                pathname.  For the MVS server.  it only makes sense for
  1590.                the pathname to be a REXX exec specification.  The path
  1591.                and the user's string are given to the host, which
  1592.                returns a menu of selections.  See also WHOIS.
  1593.    TELNET    - the item is a Telnet server.
  1594.                The path name is ignored.  The port number should be
  1595.                omitted or set to 0, unless an alternate TELNET port
  1596.                is required by the server referenced by HOST.
  1597.    TN3270    - the item is a TN3270 server.  This is like TELNET
  1598.                except that it takes you to a full-screen IBM mainframe
  1599.                terminal session.
  1600.    CSO       - the item is a CSO phonebook server.  This is a campus
  1601.                information protocol that is not an Internet standard,
  1602.                but may be available at some universities.
  1603.    WHOIS     - the item is a "whois" query.  This is similar to the
  1604.                INDEX type, except that the server returns a file
  1605.                rather than a menu.  This is not (yet) an official
  1606.                part of the Gopher protocol, though it does appear in
  1607.                certain (patched) versions of other implementations.
  1608.  
  1609.    NAME=name
  1610.  
  1611.    The descriptive string that will appear in the Gopher client's
  1612.    display of menu selections for this item.  Make this as human as
  1613.    possible.  Case is preserved.
  1614.  
  1615.    PATH=path
  1616.  
  1617.    The pathname to be passed to the Gopher server to retrieve the
  1618.    item.  See below for a fuller description.
  1619.  
  1620.    HOST=host
  1621.  
  1622.    The name of the Gopher server host that will process the request.
  1623.    See below for a fuller description.
  1624.  
  1625.    PORT=port
  1626.  
  1627.    The TCP/IP port to connect to.  For Gopher, this should always be
  1628.    port 70 (except for a TELNET or TN3270 type, whose port defaults to
  1629.    the standard TELNET port if zero or omitted).  If this is omitted,
  1630.    then the default port number is taken.
  1631.  
  1632.    END
  1633.  
  1634.    Required to keep menu entries separate.
  1635.  
  1636.  Comment lines may be freely included, starting with '#' in
  1637.  the first column of data.
  1638.  
  1639. More about Path Names
  1640.  
  1641.  Note that the format of a path depends on which Gopher server is
  1642.  going to be processing the entry, as defined by the HOST= field.
  1643.  If the entry is going to a different Gopher server, then the
  1644.  pathname format depends on that server.  For example, a Unix server
  1645.  would expect a Unix file name with a slash.
  1646.  
  1647.  A path name for the MVS Gopher may be one of the following:
  1648.  
  1649.  * A fully qualified MVS data set name, without quotes, identifying
  1650.    a sequential text data set or PDS member.  If TYPE=FILE, this is
  1651.    text.  If TYPE=DIRECTORY, this is a gopher menu as described above.
  1652.  
  1653.  * A fully qualified MVS data set name, without quotes, identifying a
  1654.    PDS (no member).  This causes the MVS Gopher server to return a
  1655.    list of member names of the PDS in Gopher directory format.  This
  1656.    is valid only with TYPE=DIRECTORY.  Member aliases are included in
  1657.    the resulting list.
  1658.  
  1659.  * A member name enclosed in parentheses.  This is treated as
  1660.    a full PDS member.  In other words, the MVS Gopher server will use
  1661.    the name of the PDS in which the menu itself was found.
  1662.    This allows you to move PDS's full of Gopher menus around without
  1663.    having to worry about changing all the path names.  This happens
  1664.    only when the menu itself is a PDS member and the host is the
  1665.    same as the local host (MVS for the server, - for local mode).
  1666.    Specifying HOST=+ is recommended for this.
  1667.  
  1668.    Each member is treated as a Gopher FILE.  The NAME field is
  1669.    set to the member name.  If you want to do anything fancier
  1670.    than this, you will have to construct your own Gopher menu.
  1671.  
  1672.  * A string "DD:ddname" or "DD:ddname(member)", identifying a file by
  1673.    MVS ddname a la C/370.  Valid with either TYPE=FILE or
  1674.    TYPE=DIRECTORY, so the ddname can point to text or a menu.
  1675.    However, if the ddname happens to be allocated to a PDS, it does
  1676.    NOT work like a directory above - it's just illegal and will
  1677.    probably cause lossage.
  1678.  
  1679.  * A string "EXEC:execname args", which specifies the name of a
  1680.    REXX exec to be executed to return the data.  Valid with any
  1681.    and all types.  To learn more about how to make use of this
  1682.    feature, please go back to the "About This Gopher" tree and
  1683.    read up on using REXX execs with MVS Gopher.
  1684.  
  1685.    If you are using your own private GOPHER data via local access
  1686.    and you want to run REXX execs, you must have a "localexec:"
  1687.    line in your GOPHERRC file identifying your REXX exec library.
  1688.  
  1689.  * A string "FTP0:ftpstuff", which specifies a remote host and a file to
  1690.    be fetched via anonymous FTP to that remote host.  This is valid with
  1691.    the FILE type (TYPE=0).
  1692.  
  1693.  * A string "FTP1:ftpstuff", which specifies a remote host and a
  1694.    anonymous FTP directory on that host to be viewed as a Gopher menu.
  1695.    This is valid with the DIRECTORY type (TYPE=1).
  1696.  
  1697.  * A string "FTPVM0:ftpstuff", which is like FTP0 except that the remote
  1698.    host is a VM/CMS machine running the "FAL" FTP server.
  1699.  
  1700.  * A string "FTPVM1:ftpstuff", which is like FTP1 except that the remote
  1701.    host is a VM/CMS machine running the "FAL" FTP server.
  1702.  
  1703.    For all of the above...
  1704.  
  1705.    Note that the HOST= and PORT= must still point to the MVS gopher
  1706.    server, which performs the remote FTP for you.
  1707.  
  1708.    In the PATH= field, the stuff after the "FTP0:" or "FTP1:" may take
  1709.    one of the following forms:
  1710.  
  1711.      ftp0:host
  1712.      ftp0:host:path
  1713.      ftp0:host:user:path
  1714.      ftp0:host:user:pass:path
  1715.      ftp1:host:path
  1716.      ftp1:host:user:path
  1717.      ftp1:host:user:pass:path
  1718.  
  1719.    If path is omitted, then path is the current directory of the remote
  1720.    anonymous FTP session.
  1721.    If user is omitted, defaults to "anonymous".
  1722.    If pass is omitted, defaults to "gopher@localhost.domain.qualifier".
  1723.  
  1724.    The syntax is defined to let path always be the last item
  1725.    just in case the path name contains a colon.
  1726.  
  1727.    For the VM variants, the directory is a minidisk specification, and
  1728.    the file is in the format minidisk/filename.filemode (no filetype).
  1729.  
  1730.    Examples:
  1731.  
  1732.    A directory type request...
  1733.  
  1734.     ftp1:boombox.micro.umn.edu:/pub/gopher/mvs
  1735.     ftpvm1:vm1.nodak.edu:powerl
  1736.  
  1737.    A file type request...
  1738.  
  1739.     ftp0:some.place.else.com:guest:guestpassword:/blah/README
  1740.     ftpvm0:vm1.nodak.edu:powerl/faq3.ann6000
  1741.  
  1742. More About Host Names
  1743.  
  1744.  You may find that some Gopher servers insist on appending the
  1745.  network's domain name to local server hostnames.  You should check
  1746.  with your network gurus to make sure that this will work with your
  1747.  TCP/IP host lookup.  The MVS server will accept hostnames either
  1748.  with or without the domain name appended - this applies to the
  1749.  specification of hostnames in the Gopher access table as well -
  1750.  but other Gopher servers may not.
  1751.  
  1752. Two special cases:
  1753.  
  1754.  A plus sign (HOST=+) means that the host is the same host as the one
  1755.  that is looking at the directory entry - i.e. the server that is
  1756.  serving up this menu.  The Gopher server simply plugs in its own host
  1757.  name at that point.  This is NOT part of the Gopher protocol, but
  1758.  merely a server hack.
  1759.  
  1760.  A minus sign (HOST=-) means that access to this item will be in
  1761.  "local" (serverless) mode.  This is recognized only by the MVS Gopher
  1762.  client.  It means that the client will do the retrieval itself,
  1763.  without asking a server to do it.
  1764.  
  1765.  The directory-processing code, when invoked in "local mode", will
  1766.  treat HOST=+ as HOST=- since the current host is the local mode
  1767.  operation in that case.  Therefore, using HOST=+ is recommended
  1768.  so that one can port one's local GOPHER menus to the public server
  1769.  at some point.
  1770.  
  1771.  A REXX exec that generates menus dynamically can use - as a hostname,
  1772.  but not +.
  1773.  
  1774. ------------------------------------------------------------------------
  1775.  
  1776.  How To Request Information Resources From Other GOPHER Servers
  1777.  
  1778. Rather than describe the standard format of a Gopher menu here,
  1779. I recommend that you go to your nearest Unix box and type
  1780.  
  1781.   man gopherd
  1782.  
  1783. That should tell you all you need to know about Unix gopher servers.
  1784. If your gopher server is on some other kind of machine, then go find
  1785. the documentation for that machine's Gopher menus.
  1786.  
  1787. The purpose of the above exercise is primarily to determine the format
  1788. of a path name understood by a given Gopher server.  Once you know that,
  1789. you can build a Gopher menu the MVS Gopher will understand, according to
  1790. the format described in the top section.  Set the host to point to
  1791. the other Gopher server, who will interpret the other items in the menu.
  1792.  
  1793. ------------------------------------------------------------------------
  1794.  
  1795. Dynamic Generation of GOPHER Menus
  1796.  
  1797.  If you want to be able to generate a Gopher menu dynamically,
  1798.  you can do this via the REXX interface.  You also must understand
  1799.  the Gopher protocol.  A Gopher menu is really a text representation
  1800.  of the actual protocol, which goes like this:
  1801.  
  1802.  filetype -tab- name -tab- path -tab- host -tab- port
  1803.  
  1804.  where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
  1805.  character, and filetype is a single character.  The filetypes
  1806.  supported by the MVS Gopher server are:
  1807.  
  1808.  0 - flat file
  1809.  1 - directory
  1810.  2 - CSO
  1811.  3 - error
  1812.  7 - index
  1813.  8 - TELNET
  1814.  T - TN3270
  1815.  w - whois (experimental)
  1816.  
  1817.  A REXX exec that wants to generate a Gopher menu must output lines
  1818.  in this format.  For more information, go back to the Gopher tree
  1819.  for "About This Gopher" and look up information on the REXX interface.
  1820.  
  1821. ./ ADD NAME=ABOUTCSR
  1822.  
  1823. =======================================================================
  1824.  
  1825.  The GOPHERRC File
  1826.  
  1827. =======================================================================
  1828.  
  1829.  When you use the GOPHER client, you need a file called GOPHERRC
  1830.  which stores information about your use of GOPHER.  If you don't
  1831.  have one, GOPHER will create it for you.  The file initially
  1832.  contains:
  1833.  
  1834.     the initial path/name/host/port specification, which tells
  1835.     GOPHER what to display on startup.  By default this is the
  1836.     standard GOPHER server info on MVS.  However, you can add
  1837.     to your GOPHERRC a specification for local GOPHER by
  1838.     editing GOPHERRC and activating one of the following:
  1839.  
  1840.     - the other "initial:" spec which points to your own startup menu,
  1841.       overriding the one you'd get otherwise
  1842.  
  1843.     - the localmenu: and localexec: lines.
  1844.  
  1845.     - the telnet: and domain: lines.
  1846.  
  1847.     localmenu: is equivalent to specifying an alternate initial:
  1848.     spec of host=- (dash) and path=localmenu_name.  When you use
  1849.     the LOCAL operand of the GOPHER command, localmenu: is what
  1850.     GOPHER looks for as the pathname if you don't provide one on
  1851.     the command.
  1852.  
  1853.     localexec: is required if you want to use your own library of
  1854.     GOPHER rexx execs.  This is valid for LOCAL access only.
  1855.  
  1856.     telnet: is required if you want to use a telnet command other
  1857.     than TELNET.  For example, UCLA's XTELNET is recommended if
  1858.     you have it (and if you don't have it, then get it).
  1859.  
  1860.     domain: is required if your installation hasn't configured
  1861.     the Gopher client to reference the correct local domain.
  1862.     This may be the case if you are using the object-code-only
  1863.     distribution, for example.  Normally when GOPHERRC is built
  1864.     upon your first use of the GOPHER client, this value should
  1865.     be set correctly.  There should never be any need to change it,
  1866.     assuming that it works properly, which you'll find out right
  1867.     away if it doesn't.
  1868.  
  1869.     Some option defaults may be stored in the GOPHERRC file
  1870.     in the future.
  1871.  
  1872.     Note that bookmarks are not stored in your GOPHERRC file.
  1873.     They are stored in separate bookmark data sets, whose names
  1874.     the client user must specify.  Do not attempt to load your
  1875.     GOPHERRC file as a bookmark file!
  1876.  
  1877.     If you have a newly created GOPHERRC file, you can read the
  1878.     comments to guide you in customizing the file.
  1879. ./ ADD NAME=ABOUTCSW
  1880.  
  1881. =======================================================================
  1882.  
  1883.  What Happens When You Start Up GOPHER?
  1884.  
  1885. =======================================================================
  1886.  
  1887.  What you see when you start up GOPHER depends on what you have
  1888.  specified, either on the command line or in the GOPHERRC file.
  1889.  In general, command operands override GOPHERRC specifications.
  1890.  
  1891.  GOPHER does its thing by connecting to a Gopher server somewhere
  1892.  on your network.  If you do not specify otherwise, this server is
  1893.  assumed to be MVS (the host where you are running this client).
  1894.  The default GOPHERRC file specifies this as the server.
  1895.  The startup menu you see is the one defined by the administrator
  1896.  of that server.
  1897.  
  1898.  You can request a different server or a different startup menu,
  1899.  either by modifying the GOPHERRC file or by specifying command
  1900.  operands.  The SERVER operand tells GOPHER to get a startup menu
  1901.  from a different server, and the PATH operand tells GOPHER what
  1902.  startup menu to request (the contents of the path depend on what
  1903.  server you point to and what it's looking for, but it is typically
  1904.  the name of a file on that system that contains a Gopher menu).
  1905.  
  1906.  You can also use GOPHER to access your own private data by requesting
  1907.  "local" (serverless) mode.  A server name of a single dash "-" means
  1908.  local access.  In this case, you must provide a path name so that
  1909.  GOPHER knows where to look for your data.  The path name is the name
  1910.  of a data set containing your GOPHER menu - it must be FULLY QUALIFIED
  1911.  AND WITHOUT QUOTES.  The path name can be provided either as a command
  1912.  operand or in the GOPHERRC file.
  1913. ./ ADD NAME=ABOUTCSX
  1914. =======================================================================
  1915.  
  1916. REXX Exec Interface
  1917.  
  1918. =======================================================================
  1919.  
  1920. You can request the MVS Gopher server (or the MVS Gopher client, in
  1921. "local" (serverless) mode) to retrieve information dynamically by
  1922. executing a REXX exec.  To request this, you define a menu entry
  1923. with the following PATH= field:
  1924.  
  1925. PATH=EXEC:execname args
  1926.  
  1927. In the case of EXEC:, the REXX exec identified by "execname" is
  1928. executed, along with the arguments "args" given.  For example:
  1929.  
  1930. PATH=EXEC:MYEXEC ANY ARGS
  1931.  
  1932. will cause the MYEXEC exec to be executed with "ANY ARGS" as the
  1933. single argument string.
  1934.  
  1935. If the TYPE is INDEX, the search string submitted by the user will be
  1936. appended to the args separated by a blank.  The exec must be able to
  1937. deal with this.
  1938.  
  1939. REXX Execs must be in a PDS allocated to DD GGEXEC.  This ddname
  1940. needs to be allocated in the Gopher server's JCL.  For local mode,
  1941. the GOPHER command will allocate the GGEXEC file to the REXX exec
  1942. library specified on the "localexec:" line in your GOPHERRC file,
  1943. if you have activated it.  Otherwise you will not be able to use
  1944. REXX execs in local mode.
  1945.  
  1946. Note that you do not need the /* REXX */ comment at the beginning of
  1947. REXX execs used by gopher (though it does not hurt to include it!)
  1948. because they are invoked by the IRXEXEC facility and not the standard
  1949. TSO CLIST/EXEC search.
  1950.  
  1951. Now, how does the REXX exec return data to the Gopher server?
  1952.  
  1953. First of all, it depends on the TYPE that the exec is expected
  1954. to return, which has nothing to do with HOW the returning is done.
  1955.  
  1956. So, first let's talk about how the exec returns data, and then
  1957. about what it is expected to return.
  1958.  
  1959. How to return data
  1960.  
  1961. The REXX exec must return data by writing it to the SYSTSPRT DD.
  1962. Note that this is where normal TSO output goes when a REXX exec
  1963. is run in TSO batch.  However, since REXX execs are invoked by
  1964. the IRXEXEC interface by the Gopher server, to prevent dependency
  1965. on a TSO environment, this default behavior of REXX/TSO cannot
  1966. be relied upon.  Therefore, if you write a REXX exec to return
  1967. Gopher data, you must explicitly send the output to the SYSTSPRT
  1968. ddname.  The Gopher server makes sure that it can read this data.
  1969.  
  1970. A typical approach is to queue all the output to the REXX data stack,
  1971. queue a final "" and then use EXECIO.  Be careful not to queue null
  1972. lines in this case.  Be sure to protect the stack in case of lossage.
  1973. Example:
  1974.  
  1975.  "NEWSTACK"
  1976.  do while more_data_to_get
  1977.   some_data = get_some_data()
  1978.   if some_data = "" then queue " "
  1979.   else queue some_data
  1980.  end
  1981.  queue ""
  1982.  "EXECIO * DISKW SYSTSPRT (FINIS)"
  1983.  "DELSTACK"
  1984.  
  1985. You can also create a stem variable to hold the output, if you
  1986. want to avoid problems with null lines or nested stacks.  Example:
  1987.  
  1988.  do i = 1 to whatever
  1989.    foo.i = get_some_data()
  1990.  end
  1991.  foo.0 = i
  1992.  "EXECIO * DISKW SYSTSPRT (FINIS STEM FOO.)"
  1993.  
  1994. A downside is that if the REXX exec finds anomalous conditions
  1995. or executes a TSO command that barfs, standard TSO command output
  1996. will probably get lost.  Therefore, try to use OUTTRAP to capture
  1997. command output and test for error codes, and write all captured
  1998. output or error messages to SYSTSPRT in such a way as to allow
  1999. the client to see them (but not treat them as normal directory
  2000. data or whatever).
  2001.  
  2002. A helpful hack is to use an EXECUTE exec to invoke other REXX
  2003. code or TSO commands that normally output via PUTLINE.  e.g.:
  2004.  
  2005. /* REXX. Usage: EXECUTE exec args... */
  2006.  
  2007.  parse arg real_exec_command
  2008.  parse source sourceline
  2009.  if word(sourceline,7) = "TSO" then do
  2010.   x = outtrap("LINE.")
  2011.   real_exec_command
  2012.   arc = rc
  2013.   x = outtrap("OFF")
  2014.   "EXECIO * DISKW SYSTSPRT (FINIS STEM LINE.)"
  2015.  end
  2016.  else do
  2017.   real_exec_command
  2018.   arc = rc
  2019.  end
  2020.  
  2021.  return arc
  2022.  
  2023. I don't recommend this, though, because it's SLOW.
  2024.  
  2025.  
  2026. If the Gopher server is a TSO-in-batch job (i.e. EXEC PGM=IKJEFT01)
  2027. then you can issue TSO commands from the exec.  To get the output,
  2028. though, you need to use OUTTRAP around them.  If they issue TPUT's,
  2029. you are SOL.  If they are PL/1 programs that write to SYSPRINT, or
  2030. FORTRAN or assembler, etc., allocate the SYSPRINT or FT06F001 or
  2031. whatever file to a temporary and copy the temporary to SYSTSPRT.  If
  2032. it is a C/370 program that writes to stdout or stderr, you may be able
  2033. to use redirection:
  2034.  
  2035.    CALL 'THEIR.LOAD(CPROG)' 'args > DD:SYSTSPRT'
  2036.  
  2037.  for stdout
  2038.  
  2039.    CALL 'THEIR.LOAD(CPROG)' 'args 2> DD:SYSTSPRT'
  2040.  
  2041.  for stderr
  2042.  
  2043.  (for multiple output, use >> instead of >)
  2044.  
  2045.  If gopher server is run straight batch rather than as a TSO job, then
  2046.  you cannot run REXX execs that require a TSO environment.
  2047.  
  2048.  One more important word:  Make sure that your SYSTSPRT file has a
  2049.  large enough LRECL to handle the REXX output.  If it is too short,
  2050.  the REXX output will get folded.  For TYPE=DIRECTORY in particular,
  2051.  this is disastrous.  Recommended JCL for executing the Gopher server
  2052.  may be found elsewhere in the installation materials, or your MVS
  2053.  system programmer has probably already installed a Gopher server in
  2054.  'SYS1.PROCLIB' or the equivalent with the correct allocation.
  2055.  
  2056. What it is expected to return
  2057.  
  2058.  OK - now the good stuff.  This depends on the TYPE on the menu entry
  2059.  that your exec is trying to fulfill.  Some gopher protocol basics:
  2060.  
  2061.  A Gopher menu is really a text representation of the actual protocol,
  2062.  which goes like this:
  2063.  
  2064.  filetype name -tab- path -tab- host -tab- port
  2065.  
  2066.  where -tab- is the EBCDIC (on MVS) or ASCII (on other box) tab
  2067.  character, and filetype is a single character.  The filetypes
  2068.  supported by the MVS Gopher server are:
  2069.  
  2070.  0 - flat file
  2071.  1 - directory
  2072.  2 - CSO
  2073.  3 - error
  2074.  7 - index
  2075.  8 - TELNET
  2076.  T - TN3270
  2077.  w - whois (experimental)
  2078.  
  2079.  To generate the equivalent of a Gopher menu, you must output data
  2080.  in the above format.  Now for the details...
  2081.  
  2082. TYPE=FILE
  2083.  
  2084. Just return the straight data.  Try to avoid null lines because C/370
  2085. believes they don't exist and will throw them away.  We hate this, but
  2086. IBM is so hard to convince of reality sometimes...  Change all null
  2087. lines to lines containing one blank as you write them out (you need to
  2088. do this anyway if you are queueing output on the stack for EXECIO) and
  2089. you will have no problems.
  2090.  
  2091. TYPE=DIRECTORY
  2092.  
  2093. You must return lines that fit the gopher protocol format as above.
  2094.  
  2095. For example, if you want to generate a Gopher menu on the fly that
  2096. is equivalent to this:
  2097.  
  2098. type=file
  2099. name=This is my description
  2100. path=some.gopher.path
  2101. host=sun1.sanjuan.com
  2102. port=70
  2103.  
  2104. then you output a line that looks like this:
  2105.  
  2106.   0This is my description!some.gopher.path!sun1.sanjuan.com!70
  2107.  
  2108. (each ! is really a tab (EBCDIC hex 05) character)
  2109.  
  2110. where "0" is the type (file in this example, but would be "1" for
  2111. type=directory, "7" for typeindex, etc.)
  2112.  
  2113. Here's the REXX code that might do this:
  2114.  
  2115. name = "This is my description"
  2116. path = "some.gopher.path"
  2117. host = "sun1.sanjuan.com"
  2118. tab  = '05'x
  2119. port = 70
  2120.  
  2121. queue "0"||name||tab||path||tab||host||tab||port
  2122.  
  2123. Assuming we write the queued lines to DD SYSTSPRT, as described.
  2124.  
  2125. Specifying the Right Host Name
  2126.  
  2127. Most of the time you will probably want to generate a menu item
  2128. that points back to your MVS host, not some other host.  It may
  2129. even redrive your selfsame REXX exec with new arguments.  And if
  2130. the exec was invoked in local (serverless) mode, you want the item
  2131. to get driven in the same mode, probably.
  2132.  
  2133. The question is - what's the easiest way to identify what
  2134. the "same server" is?  One way is to hardcode the server name (e.g.
  2135. "MVS.DRAPER.COM"), but this is not sufficiently general because:
  2136.  
  2137. (1) the server name or location may change
  2138. (2) you can't distribute the exec to other Gopher users
  2139. (3) it won't work the same way in "local mode"
  2140.  
  2141. So, you need a way to know what the name of your selfsame host is.
  2142. The MVS Gopher server can use HOST=+, but you can't, as that isn't
  2143. part of the Gopher protocol.  So what do you do?
  2144.  
  2145. Recommendation:  call a function hostname() to return the current
  2146. host name.  So in the above code segment, you might have:
  2147.  
  2148.  host = hostname()
  2149.  
  2150. What is that hostname() function anyway?
  2151. Well, you create it.
  2152. Take your Gopher exec library (please) and include an exec
  2153. called HOSTNAME, which you set up to return the name
  2154. of the host that you want to be the "same host".
  2155.  
  2156. Note that a plus sign "+" will not work in this context.
  2157. The plus sign is a hack interpreted by the Gopher server
  2158. when it sees it on a menu.  It is *not* part of the Gopher
  2159. protocol and therefore cannot be sent over.
  2160.  
  2161. However, the minus sign "-" will work, as the Gopher client
  2162. in local mode will interpret it at the protocol level
  2163. (which DOES NOT IMPLY THAT IT IS A PART OF THE STANDARD
  2164. GOPHER PROTOCOL, PROPOSED OR OTHERWISE - THIS IS JUST A
  2165. LOCAL HACK MODIFICATION).
  2166.  
  2167. Anyhow, what you ought to do is to have different Gopher
  2168. exec libraries for local (i.e.private) use and public
  2169. server use.  The public server will have a HOSTNAME member
  2170. that says
  2171.  
  2172.  return "MVS.DRAPER.COM"
  2173.  
  2174. or whatever the name of *YOUR* gopher server host is.
  2175.  
  2176. Your private exec library should have a HOSTNAME member
  2177. that says
  2178.  
  2179.   return "-"
  2180.  
  2181. This is the best I can come up with right now.  A future enhancement
  2182. may be to pass the hostname as the second arg to the REXX exec using
  2183. the IRXEXEC interface, e.g.
  2184.  
  2185. parse arg execargs, hostname
  2186.  
  2187. Then we could pass even more such arguments, like port, etc.
  2188. But that's all for now...
  2189.  
  2190.  
  2191. Oh, one more thing!  The same principle applies to the port number.
  2192. Yes, it's normally 70 for Gopher.  But if you're running a server
  2193. off a different port - like the example of running two MVS Gopher
  2194. servers you saw if you read the installation files - then you will
  2195. not want to hardcode a port number either.
  2196.  
  2197. So in all the above examples, change the statements that read
  2198. "port = 70" or the like so that they read
  2199.  
  2200. port = port()
  2201.  
  2202. and define a PORT exec in your library, sort of like the HOSTNAME exec,
  2203. that reads
  2204.  
  2205. return "70"            /* if you want to talk to the primary server */
  2206.  
  2207.  or
  2208.  
  2209. return "1570"          /* use secondary Gopher server */
  2210.  
  2211. Note that in our recommended scenario, we always use the secondary
  2212. server for exec requests and the primary server for file requests.
  2213. So, if you are building a menu item whose path is a file name, use
  2214. the primary server port; if you are building a menu item whose path
  2215. is a REXX exec specification, use the secondary server port.
  2216.  
  2217. ./ ADD NAME=ABOUTS
  2218. gopher_menu
  2219.  
  2220. TYPE=FILE
  2221. NAME=Creating MVS Gopher Menus
  2222. PATH=(ABOUTCSM)
  2223. HOST=+
  2224. END
  2225.  
  2226. TYPE=FILE
  2227. NAME=MVS Gopher Access Table
  2228. PATH=(ABOUTSA)
  2229. HOST=+
  2230. END
  2231.  
  2232. TYPE=FILE
  2233. NAME=MVS Gopher Startup Parameters
  2234. PATH=(ABOUTSP)
  2235. HOST=+
  2236. END
  2237.  
  2238. TYPE=FILE
  2239. NAME=REXX Exec Interface
  2240. PATH=(ABOUTCSX)
  2241. HOST=+
  2242. END
  2243.  
  2244. ./ ADD NAME=ABOUTSA
  2245.  
  2246.   Format of entries in the Gopher Access Table:
  2247.  
  2248.   filename (fully qualified, all uppercase, no quotes)
  2249.   can be "DD:DDNAME" or "EXEC:EXECNAME"
  2250.  
  2251.   followed by names of hosts which are authorized to access the data.
  2252.   If no host name list is present, all hosts are authorized
  2253.  
  2254.   You may specify the same file name more than once, if you need
  2255.   more lines to put host names on.
  2256.  
  2257.   Individual PDS members must be specified separately.  A PDS without
  2258.   a member name establishes access only to the PDS directory.
  2259.  
  2260.   Note that the default directory MUST be in this table.
  2261.  
  2262.   Also note that in the case of EXECs, the EXEC must live in the
  2263.   library allocated to GGEXEC in the Gopher server JCL.
  2264.  
  2265.   *** ANY DATA SET REFERENCED BY ANY EXEC IN THAT LIBRARY IS FULLY
  2266.   *** ACCESSIBLE TO GOPHER REGARDLESS OF THIS TABLE!  USE THIS TABLE
  2267.   *** TO GOVERN CONTROL TO THE EXEC ITSELF!!!
  2268.  
  2269. ./ ADD NAME=ABOUTSP
  2270.  
  2271.  MVS Gopher Startup Parameter File
  2272.  
  2273.  The Gopher server started task may contain a DD statement pointing
  2274.  to DDname GGPARMS.  If so, this file contains startup parameters
  2275.  for that invocation of the server.  If such a file does not exist,
  2276.  the defaults (as in the header file GGUSER) are used.
  2277.  
  2278.  One possible use of this feature is to have more than one MVS Gopher
  2279.  server running, with different port numbers.  This may prevent some
  2280.  bottlenecking situations.
  2281.  
  2282.  All entries in this file have the format:   variable value comments
  2283.  
  2284.  These are the possible values and their default settings:
  2285.  
  2286.  mtftasks 1    Number of concurrent subtasks to handle client requests
  2287.  port     70   The TCP port number by which clients connect
  2288.  qlength  20   Queue length for TCP server listen function
  2289.  timeout  60   Connection timeout specified when socket is closed
  2290.  domain   .DRAPER.COM     The suffix to be appende to bald host names
  2291.  
  2292. You may notice that the TELNET command may be set in this file too.
  2293. That was probably a misunderstanding, as it's the client, not the
  2294. server, that controls how telnets are to be done.
  2295.  
  2296. ./ ADD NAME=ABOUTW
  2297. What is Gopher?
  2298.  
  2299. For more information, read the FAQ, posted to USENET newsgroups
  2300. comp.infosystems.gopher and news.answers every two weeks.
  2301.  
  2302. The information contained here is borrowed therefrom in large part.
  2303.  
  2304. Gopher is a client/server protocol for building a distributed
  2305. information delivery service.  While providing a delivery vehicle for
  2306. local information, Gopher also facilitates access to other Gopher and
  2307. information servers on the Internet.
  2308.  
  2309. Gopher servers and clients can be obtained via anonymous ftp to
  2310. boombox.micro.umn.edu.  Look in the directory /pub/gopher.
  2311.  
  2312.      There are clients for the following systems.  For the latest
  2313.      directory information, see the FAQ.
  2314.  
  2315.       Unix Curses & Emacs
  2316.       Xwindows
  2317.       Macintosh Hypercard
  2318.       Macintosh Application
  2319.       DOS w/Clarkson Driver
  2320.       NeXTstep
  2321.       VM/CMS
  2322.       VMS
  2323.       MVS
  2324.  
  2325.      There are also a number of public telnet login sites available.
  2326.      See the FAQ for more information.
  2327.  
  2328.      There are servers for the following systems.  For the latest
  2329.      directory information, see the FAQ.
  2330.  
  2331.        Unix
  2332.        VMS
  2333.        Macintosh
  2334.        VM/CMS
  2335.        MVS
  2336.  
  2337.  
  2338. Papers and articles describing Gopher:
  2339.  
  2340.      _The_Internet_Gopher_, "ConneXions", July 1992, Interop.
  2341.  
  2342.      _Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
  2343.  
  2344.      _The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
  2345.           IETF, CNRI, Section 5.3
  2346.  
  2347.      _Internet_Gopher_, Proceedings of Canadian Networking '92
  2348.  
  2349.      _The_Internet_Gopher_, INTERNET: Getting Started, SRI
  2350.           International, Section 10.5.5
  2351.  
  2352.      _Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
  2353.           July 20, 1992
  2354.  
  2355.      Gopher will also be in two forthcoming O'Reilly Books:
  2356.      "Administrating TCP/IP, and The Whole Internet"
  2357.  
  2358. ./ ADD NAME=FAQ
  2359. Xref: news.draper.com comp.infosystems.gopher:3051 news.answers:5459 comp.answer
  2360. Newsgroups: comp.infosystems.gopher,news.answers,comp.answers
  2361. Path: news.draper.com!ns.draper.com!noc.near.net!howland.reston.ans.net!gatech!n
  2362. From: gopher@boombox.micro.umn.edu (UofMN Gopher Team)
  2363. Subject: Gopher (comp.infosystems.gopher) Frequently Asked Questions (FAQ)
  2364. Message-ID: <goher-faq_03-26-93@mudhoney.micro.umn.edu>
  2365. Followup-To: comp.infosystems.gopher
  2366. Summary: Common Questions and Answers about the Internet Gopher, a
  2367.         client/server protocol for making a world wide information
  2368.         service, with many implementations.
  2369. Sender: news@news.cis.umn.edu (Usenet News Administration)
  2370. Supersedes: <gopher-faq_02-19-93@mudhoney.micro.umn.edu>
  2371. Nntp-Posting-Host: mudhoney.micro.umn.edu
  2372. Reply-To: gopher@boombox.micro.umn.edu (UofMN Gopher Team)
  2373. Organization: University of Minnesota
  2374. Date: Fri, 26 Mar 1993 09:29:40 GMT
  2375. Approved: news-answers-request@MIT.Edu
  2376. Lines: 562
  2377.  
  2378. Archive-name: gopher-faq
  2379. Last-modified: 1993/03/11
  2380.  
  2381. Common Questions and Answers about the Internet Gopher, a
  2382. client/server protocol for making a world wide information service,
  2383. with many implementations.  Posted to comp.infosystems.gopher,
  2384. comp.answers, and news.answers every two weeks.
  2385.  
  2386. The most recent version of this FAQ can be gotten through gopher, or
  2387. via anonymous ftp:
  2388.  
  2389. pit-manager.mit.edu:/pub/usenet/news.answers/gopher-faq
  2390.  
  2391. Those without FTP access should send e-mail to mail-server@rtfm.mit.edu
  2392. with "send usenet/news.answers/finding-sources" in the body to find out
  2393. how to do FTP by e-mail.
  2394.  
  2395. -------------------------------------------------------------------
  2396. List of questions in the Gopher FAQ:
  2397.  
  2398. Q0:  What is Gopher?
  2399. Q1:  Where can I get Gopher software?
  2400. Q2:  What do I need to access Gopher?
  2401. Q3:  Where are there publicly available logins for Gopher?
  2402. Q4:  How can I add to the information in gopher?
  2403. Q5:  Who Develops Gopher Software?
  2404. Q6:  How can I set up a "CSO" phone book server?  Where is the software?
  2405. Q7:  Why can't I access the University of Minnesota's UPI news?
  2406. Q9:  What are the type characters for the different Gopher Objects?
  2407. Q10: When I do full-text searches I always get every document back, Why?
  2408. Q11: When I try to build the UNIX software I get an error from make:
  2409.      "Must be a separator on rules line #. Stop"  Why?
  2410. Q12: What is the relationship between Gopher and (WAIS, WWW, ftp)?
  2411. Q13: Are papers or articles describing Gopher available?
  2412. Q14: On a DECstation I get the error message "/etc/svc.conf no such file
  2413.      or directory" when running the gopherd server, why?
  2414. Q15: The boolean searching terms don't work for my full-text index, why?
  2415. Q16: When linking the Unix gopher server with WAIS I get undefined symbols,
  2416. Q18: Why don't my WAIS indexes work?  I never get anything back for searches.
  2417.      or Why do I get "Dangling file" error messages in my logfile?
  2418. Q19: My gopher server doesn't work under inetd, why?
  2419. Q20: This is not a bug report, just a curiousity. I managed to install
  2420. Q21: Help!  I have PC-NFS and want to use the PC-Gopher client.  How?
  2421. Q22: How do I nuke a hung TCP connection?  I can't restart my UNIX
  2422.      gopher server unless I get rid of it, and I don't want to reboot!
  2423. Q23: Is there somewhere I can retrieve a list of announced gopher
  2424.      links?  I'd like to keep a local, up-to-date list of available gopher
  2425.      holes without requiring our users to gopher to umn just to scan
  2426.      GopherSpace.
  2427. Q24: Why doesn't my unix gopher client display ISO-Latin-1 characters
  2428. Q25: What is veronica?
  2429.  
  2430. -------------------------------------------------------------------
  2431. Q0:  What is Gopher?
  2432.  
  2433. A0:  The Internet Gopher client/server provides a distributed
  2434.      information delivery system around which a world/campus-wide
  2435.      information system (CWIS) can readily be constructed.   While
  2436.      providing a delivery vehicle for local information,  Gopher
  2437.      facilitates access to other Gopher and information servers
  2438.      throughout the world.
  2439.  
  2440. -------------------------------------------------------------------
  2441. Q1:  Where can I get Gopher software?
  2442.  
  2443. A1:  via anonymous ftp to boombox.micro.umn.edu.  Look in the directory
  2444.      /pub/gopher
  2445.  
  2446. --------------------------------------------------------------------
  2447. Q2:  What do I need to access Gopher?
  2448.  
  2449. A2:  You will need a gopher "client" program that runs on your local PC
  2450.      or workstation
  2451.  
  2452.      There are clients for the following systems.  The directory
  2453.      following the name is the location of the client on the anonymous
  2454.      ftp site boombox.micro.umn.edu (134.84.132.2) in the directory
  2455.      /pub/gopher.
  2456.  
  2457.       Unix Curses & Emacs   :  /pub/gopher/Unix/gopher1.12.tar.Z
  2458.       Xwindows (athena)     :  /pub/gopher/Unix/xgopher1.2.tar.Z
  2459.       Xwindows (Motif)      :  /pub/gopher/Unix/moog
  2460.       Macintosh Hypercard   :  /pub/gopher/Macintosh-TurboGopher/old-versions *
  2461.       Macintosh Application :  /pub/gopher/Macintosh-TurboGopher *
  2462.       DOS w/Clarkson Driver :  /pub/gopher/PC_client/
  2463.       NeXTstep              :  /pub/gopher/NeXT/
  2464.       VM/CMS                :  /pub/gopher/Rice_CMS/ or /pub/gopher/VieGOPHER/
  2465.       VMS                   :  /pub/gopher/VMS/
  2466.       OS/2 2.0              :  /pub/gopher/os2/
  2467.       MVS/XA                :  /pub/gopher/mvs/
  2468.  
  2469.      Many other clients and servers have been developed by others, the
  2470.      following is an attempt at a comprehensive list.
  2471.  
  2472.       A Microsoft Windows Winsock client "The Gopher Book"
  2473.         sunsite.unc.edu:/pub/micro/pc-stuff/ms-windows/winsock/goph_tbk.zip
  2474.  
  2475.       A Macintosh Application, "MacGopher".
  2476.         ftp.cc.utah.edu:/pub/gopher/Macintosh *
  2477.  
  2478.       Another Macintosh application, "GopherApp".
  2479.         ftp.bio.indiana.edu:/util/gopher/gopherapp *
  2480.  
  2481.       A port of the UNIX curses client for DOS with PC/TCP
  2482.         oac.hsc.uth.tmc.edu:/public/dos/misc/dosgopher.exe
  2483.  
  2484.       A port of the UNIX curses client for PC-NFS
  2485.          bcm.tmc.edu:/nfs/gopher.exe
  2486.  
  2487.       A beta version of the PC Gopher client for Novell's LAN Workplace
  2488.       for DOS
  2489.          lennon.itn.med.umich.edu:/dos/gopher
  2490.  
  2491.       A VMS DECwindows client for use with Wollongong or UCX
  2492.          job.acs.ohio-state.edu:XGOPHER_CLIENT.SHARE
  2493.  
  2494.  
  2495.      * Note: these Macintosh clients require MacTCP.
  2496.  
  2497.      Most of the above clients can also be fetched via a gopher client
  2498.      itself.  Put the following on a gopher server:
  2499.  
  2500.        Type=1
  2501.        Host=boombox.micro.umn.edu
  2502.        Port=70
  2503.        Path=
  2504.        Name=Gopher Software Distribution.
  2505.  
  2506.  
  2507.      Or point your gopher client at boombox.micro.umn.edu, port 70 and
  2508.      look in the gopher directory.
  2509.  
  2510.  
  2511.      There are also a number of public telnet login sites available.
  2512.      The University of Minnesota operates one on the machine
  2513.      "consultant.micro.umn.edu" (134.84.132.4) See Q3 for more
  2514.      information about this.  It is recommended that you run the client
  2515.      software instead of logging into the public telnet login sites.  A
  2516.      client uses the custom features of the local machine (mouse,
  2517.      scroll bars, etc.)  A local client is also faster.
  2518.  
  2519. ---------------------------------------------------------------------
  2520. Q3:  Where are there publicly available logins for Gopher?
  2521.  
  2522. A3:  Here is a short list, use the site closest to you to minimize
  2523.      network lag.
  2524.  
  2525.      Non-tn3270 Public Logins:
  2526.  
  2527.      Hostname                  IP#              Login   Area
  2528.      ------------------------- ---------------  ------  -------------
  2529.      consultant.micro.umn.edu  134.84.132.4     gopher  North America
  2530.      gopher.uiuc.edu           128.174.33.160   gopher  North America
  2531.      panda.uiowa.edu           128.255.40.201   panda   North America
  2532.      gopher.sunet.se           192.36.125.2     gopher  Europe
  2533.      info.anu.edu.au           150.203.84.20    info    Australia
  2534.      gopher.chalmers.se        129.16.221.40    gopher  Sweden
  2535.      tolten.puc.cl             146.155.1.16     gopher  South America
  2536.      ecnet.ec                  157.100.45.2     gopher  Ecuador
  2537.  
  2538.      tn3270 Public Logins:
  2539.  
  2540.      Hostname                  IP#              Login   Area
  2541.      ------------------------- ---------------  ------  -------------
  2542.      pubinfo.ais.umn.edu       128.101.109.1    -none-  North America
  2543.  
  2544.  
  2545.      It is recommended that you run the client software instead of
  2546.      logging into the public login sites.  A client uses the
  2547.      custom features of the local machine (mouse, scroll bars, etc.)
  2548.      and gives faster response.
  2549.  
  2550. ---------------------------------------------------------------------
  2551. Q4:  How can I add to the information in gopher?
  2552.  
  2553. A4:  You can do this by running a gopher server.  Servers are available
  2554.      for a number of systems.  Use anonymous ftp to
  2555.      boombox.micro.umn.edu (134.84.132.2) and look in /pub/gopher.  The
  2556.      following servers are available there:
  2557.  
  2558.        Unix      : /pub/gopher/Unix/gopherxx.tar.Z
  2559.        VMS       : /pub/gopher/VMS/
  2560.        Macintosh : /pub/gopher/Mac_server/
  2561.        VM/CMS    : /pub/gopher/Rice_CMS/ or /pub/gopher/Vienna_CMS/
  2562.        MVS       : /pub/gopher/mvs/
  2563.        DOS PC    : /pub/gopher/PC_server/
  2564.  
  2565.  
  2566.      When you have your server ready you can publish it to the world by
  2567.      sending e-mail to the maintainters of the "Other gophers" list:
  2568.  
  2569.      If your gopher server is in Europe, send mail to:
  2570.  
  2571.         gopher@ebone.net
  2572.  
  2573.      Otherwise send mail to:
  2574.  
  2575.         gopher@boombox.micro.umn.edu
  2576.  
  2577. ---------------------------------------------------------------------
  2578. Q5:  Who Develops Gopher Software?
  2579.  
  2580. A5:  Gopher was originally developed in April 1991 by the University
  2581.      of Minnesota Microcomputer, Workstation, Networks Center to help
  2582.      our campus find answers to their computer questions.
  2583.  
  2584.      It has since grown into a full-fledged World Wide Information
  2585.      System used by a large number of sites in the world.
  2586.  
  2587.      Many people have contributed to the project, too numerous to
  2588.      count.
  2589.  
  2590.      The people behind the much of the gopher software can be reached
  2591.      via e-mail at gopher@boombox.micro.umn.edu, or via paper mail:
  2592.  
  2593.       Internet Gopher Developers
  2594.       100 Union St. SE #190
  2595.       Minneapolis, MN 55455  USA
  2596.  
  2597.      Or via FAX at:
  2598.  
  2599.       +1 (612) 625-6817
  2600.  
  2601. ---------------------------------------------------------------------
  2602. Q6:  How can I set up a "CSO" phone book server?  Where is the software?
  2603.  
  2604. A6:  CSO phone book servers are also known as "qi" servers.  The
  2605.      software implementation can be gotten via anonymous ftp from
  2606.      uxc.cso.uiuc.edu (128.174.5.50) as /pub/qi.tar.Z.  You may also
  2607.      see this referred to as "ph", which is what most of the clients
  2608.      are called.  A collected set of clients for Macs, PCs, VMS, VM,
  2609.      etc, are in the /pub/ph.tar.Z file.
  2610.  
  2611.      There is also an archive of the mailing list for qi/ph software on
  2612.      the same machine.  It's in /pub/info-ph.archive. You may join the
  2613.      list by sending email to info-ph-request@uxc.cso.uiuc.edu.
  2614.  
  2615.      This software is supported by Paul Pomes <p-pomes@uiuc.edu>
  2616.      Contact him for more information.
  2617.  
  2618. -------------------------------------------------------------------
  2619. Q7:  Why can't I access the University of Minnesota's UPI news?
  2620.  
  2621. A7:  The University of Minnesota has a site license for UPI news, we
  2622.      are not allowed to distribute it off of our campus.  We get our
  2623.      UPI news from Clarinet.  For more information about getting UPI
  2624.      news send mail to info@clarinet.com.  For information about
  2625.      setting up your own gopher-UPI server search the gopher-news
  2626.      archive for UPI.
  2627.  
  2628. -------------------------------------------------------------------
  2629. Q9:  What are the type characters for the different Gopher Objects?
  2630.  
  2631. A9:  Normal IDs.
  2632.  
  2633.      0       Item is a file
  2634.      1       Item is a directory
  2635.      2       Item is a CSO (qi) phone-book server
  2636.      3       Error
  2637.      4       Item is a BinHexed Macintosh file.
  2638.      5       Item is DOS binary archive of some sort.
  2639.      6       Item is a UNIX uuencoded file.
  2640.      7       Item is an Index-Search server.
  2641.      8       Item points to a text-based telnet session.
  2642.      9       Item is a binary file!  Client must read until the connection
  2643.                  closes.  Beware.
  2644.      T       TN3270 connection.
  2645.  
  2646.      Experimental IDs.
  2647.  
  2648.      s       Sound type.  Data stream is a mulaw sound.
  2649.      g       GIF type.
  2650.      M       MIME type.  Item contains MIME data.
  2651.      h       html type.
  2652.      I       Image type.
  2653.      i       "inline" text type (used by panda).
  2654.  
  2655. -------------------------------------------------------------------
  2656. Q10: When I do full-text searches I always get every document back, Why?
  2657.  
  2658. A10: This is a problem occasionally encountered with Unix full-text
  2659.      indexes.  It is caused by setting up the link incorrectly to a
  2660.      gindexd port.
  2661.  
  2662.      The Path= field should be *blank* when pointing to a gindexd
  2663.      index.
  2664.  
  2665.      Otherwise the client will send the path to the gindexd daemon,
  2666.      which interprets everything as a keyword.  This path is
  2667.      likely to contain a pathname that is common to all of the indexed
  2668.      files.  Thus a search generates hits on everything.
  2669.  
  2670. -------------------------------------------------------------------
  2671. Q11: When I try to build the UNIX software I get an error from make:
  2672.      "Must be a separator on rules line #. Stop"  Why?
  2673.  
  2674. A11: This is a problem with older makes that don't understand the "include"
  2675.      keyword.  One easy way to cope with this problem is compiling GNU
  2676.      make, which does understand the include keyword.
  2677.  
  2678.      If this is too difficult, remove the line:
  2679.  
  2680.       include Makefile.config
  2681.  
  2682.      from all the Makefiles and paste in a copy of Makefile.config at
  2683.      the top of each Makefile.
  2684.  
  2685.      Or, instead of pasting you can make the client/server by going
  2686.      into the appropriate directory and typing:
  2687.  
  2688.       make -f ../Makefile.config -f Makefile
  2689.  
  2690. -------------------------------------------------------------------
  2691. Q12: What is the relationship between Gopher and (WAIS, WWW, ftp)?
  2692.  
  2693. A12: Gopher is intimately intertwined with these two other systems.
  2694.      As shipped the Unix gopher server has the capability to:
  2695.  
  2696.        - Search local WAIS indices.
  2697.        - Query remote WAIS servers and funnel the results to gopher
  2698.          clients.
  2699.        - Query remote ftp sites and funnel the results to gopher
  2700.          clients.
  2701.        - Be queried by WWW (World Wide Web) clients (either using
  2702.          built in gopher querying or using native http querying.
  2703.  
  2704. -------------------------------------------------------------------
  2705. Q13: Are papers or articles describing Gopher available?
  2706.  
  2707. A13: Gopher has a whole chapter devoted to it in :
  2708.  
  2709.      _The_Whole_Internet_users_guide_and_catalog by Ed Krol
  2710.      (publisher O'Reilley & Associates, Inc; ISBN: 1-56592-025-2).
  2711.      (Editors note: ...Great book, go out and buy a bunch!)
  2712.  
  2713.      _The_Internet_Passport: NorthWestNet's Guide to Our World Online"
  2714.      By Jonathan Kochmer and NorthWestNet. Published by NorthWestNet,
  2715.      Bellevue, WA. 1993. 516 pp. ISBN 0-9635281-0-6.
  2716.      Contact info: passport@nwnet.net, or (206) 562-3000
  2717.  
  2718.      _A_Students_Guide_to_UNIX by Harley Hahn. (publisher McGraw Hill,
  2719.      Inc.; 1993 ISBN 0-07-025511-3)
  2720.  
  2721.  
  2722.      Other references include:
  2723.  
  2724.      _The_Internet_Gopher_, "ConneXions", July 1992, Interop.
  2725.  
  2726.      _Exploring_Internet_GopherSpace_ "The Internet Society News", v1n2 1992,
  2727.  
  2728.      (You can subscribe to the Internet Society News by sending e-mail to
  2729.       isoc@nri.reston.va.us)
  2730.  
  2731.      _The_Internet_Gopher_Protocol_, Proceedings of the Twenty-Third
  2732.           IETF, CNRI, Section 5.3
  2733.  
  2734.      _Internet_Gopher_, Proceedings of Canadian Networking '92
  2735.  
  2736.      _The_Internet_Gopher_, INTERNET: Getting Started, SRI
  2737.           International, Section 10.5.5
  2738.  
  2739.      _Tools_help_Internet_users_discover_on-line_treasures, Computerworld,
  2740.           July 20, 1992
  2741.  
  2742.      _TCP/IP_Network_Administration_, O'Reilly.
  2743.  
  2744.       Balakrishan, B. (Oct 1992)
  2745.         "SPIGopher: Making SPIRES databases accessible through the
  2746.       Gopher protocol".  SPIRES Fall '92 Workshop, Chapel Hill, North
  2747.       Carolina.
  2748.  
  2749.       Tomer, C.  Information Technology Standards for Libraries,
  2750.       _Journal of the American Society for Information Science_,
  2751.       43(8):566-570, Sept 1992.
  2752.  
  2753.  
  2754. -------------------------------------------------------------------
  2755. Q14: On a DECstation I get the error message "/etc/svc.conf no such file
  2756.      or directory" when running the gopherd server, why?
  2757.  
  2758. A14: This is caused by the chroot() call in gopherd.  It can be easily
  2759.      fixed by running gopherd with the -c option.
  2760.  
  2761.      Alternatively you can copy /etc/svc.conf into a directory named
  2762.      "etc" inside the gopher-data directory.
  2763. -------------------------------------------------------------------
  2764. Q15: The boolean searching terms don't work for my full-text index, why?
  2765.  
  2766. A15: This is probably because the searching is being provided by WAIS.
  2767.      WAIS opts to return all documents that contain a search phrase
  2768.      within certain limits.  WAIS searches do return the documents with
  2769.      the highest "score" at the top, those documents will have the
  2770.      closest relevance.
  2771.  
  2772.      Alternatively you could get a booleanized version of wais from
  2773.      ftp.bio.indiana.edu.
  2774. -------------------------------------------------------------------
  2775. Q16: When linking the Unix gopher server with WAIS I get undefined
  2776.      symbols,
  2777.        such as:
  2778.  
  2779.          log_file_name
  2780.          logfile
  2781.          PrintStatus
  2782.          find_value
  2783.          Sources
  2784.          NumSources
  2785.  
  2786. A17: This happens if you make gopherd before linking in the WAIS ir/ui
  2787.      directories.  The fix is to "make clean" or remove
  2788.      gopherd/{waisgopher.o,Waisindex.o} and then remake gopherd.  Or
  2789.      link the ir/ui directories first.
  2790. -------------------------------------------------------------------
  2791. Q18: Why don't my WAIS indexes work?  I never get anything back for searches.
  2792.      or Why do I get "Dangling file" error messages in my logfile?
  2793.  
  2794. A18: The problem could be in the server.  The server should be run
  2795.      using the -c option if you want WAIS to work.  Another solution is to
  2796.      patch the WAIS code so that it doesn't check the files on the disk.
  2797.      Search the gopher-news archive for "dangling".  This will turn up a
  2798.      single document with the patch.
  2799.  
  2800. -------------------------------------------------------------------
  2801. Q19: My gopher server doesn't work under inetd, why?
  2802.  
  2803. A19: It could be that your inetd server only supports a limited amount
  2804.      of arguments.  For instance, the maximum number of arguments to an
  2805.      inetd server is 5.  You can get around this by combining arguments: i.e.
  2806.  
  2807.        gopherd -I -c
  2808.  
  2809.      becomes:
  2810.  
  2811.        gopherd -Ic
  2812.  
  2813.      You may also leave the port specifier off of the command line.
  2814.      The gopher server automagically finds out the port it's running on.
  2815.  
  2816. -------------------------------------------------------------------
  2817. Q20: This is not a bug report, just a curiousity. I managed to install
  2818.      gopher on my PC, more or less by myself, which is a pretty good
  2819.      accomplishment, for someone who hasn't installed hardly anything on a
  2820.      PC. I then proceeded to load my PC/TCP kernel, ETHDRV, and try to
  2821.      start up gopher. It said it couldn't initialize that stack(?). I have
  2822.      to load this whenever I use PC/TCP. Incredibly, when I did not load
  2823.      ETHDRV, Gopher came up immediately and telneted to our local server.
  2824.      How does it know what kernel to load?
  2825.  
  2826. A20 Dr. Science says,
  2827.  
  2828.      The Internet Gopher program is not actually computer program at
  2829.      all, but a collection of magical incantations handed down from Dark
  2830.      Age conjurors.  It works by sending magical "demons" through the air,
  2831.      which scour the world for information, and then return to cast
  2832.      illusions containing the answer.
  2833.  
  2834.      When you use the Gopher, your computer isn't actually doing
  2835.      anything at all.  Instead, these demons have mesmirized you with an
  2836.      evil magical spell, which was invoked by the pattern of
  2837.      finger-movements peculiar to the typing of the letters G-O-P-H-E-R on
  2838.      your keyboard.  This spell transmits demonic information directly to
  2839.      your brain.
  2840.  
  2841.      Scientists aren't certain of the long-term effects of demonic
  2842.      mesmirization, although former presidents have suffered only minor
  2843.      medical side-effects from it.  Indeed, since Magic and Science are
  2844.      usually opposed to each other, most Scientists are usually
  2845.      close-minded about such issues, and will usually respond with some
  2846.      vacuous non-answer about "packet drivers", "stacks", and other such
  2847.      jargon.
  2848.  
  2849.      Unlike conventional scientists, Dr. Science is very open-minded and
  2850.      is willing to deal with such issues in a frank and honest manner.
  2851.      This is why people come to him with questions, and why they've learned
  2852.      to rely on and live by his answers.
  2853.  
  2854.      Dr. Science
  2855.          "I'm not a real doctor;  I have a Master's Degree....  in SCIENCE!"
  2856.  
  2857. :-) :-) :-) :-)
  2858. There's always room for a little humor in a FAQ..
  2859. -------------------------------------------------------------------
  2860. Q21: Help!  I have PC-NFS and want to use the PC-Gopher client.  How?
  2861.  
  2862. A21: Use a piece of software called PKTMUX, available at fine ftp
  2863.      sites everywhere.  This will let you use any packet driver
  2864.      application.
  2865.  
  2866.      Or, aquire a client that supports PC-NFS.  See Q2.
  2867. -------------------------------------------------------------------
  2868. Q22: How do I nuke a hung TCP connection?  I can't restart my UNIX
  2869.      gopher server unless I get rid of it, and I don't want to reboot!
  2870.  
  2871. A22:
  2872.  
  2873. Here is an example of using dbx to change a socket from CLOSING to
  2874. CLOSED.
  2875.  
  2876.  # netstat -A|grep CLOSING
  2877.  c4bc5100 tcp        0     11  mymachine.gopher 129.89.8.4.70  CLOSING
  2878.  # dbx -k /vmunix /dev/mem
  2879.  ...
  2880.  (dbx) 0xc4bc5100+8/1X                  -- display contents of PCB+8
  2881.  c4bc5108:   00000007
  2882.  (dbx) assign 0xc4bc5108=0              -- zero it
  2883.  0
  2884.  (dbx) q
  2885.  
  2886. After a minute or two, the CLOSED socket should disappear.
  2887. -------------------------------------------------------------------
  2888. Q23: Is there somewhere I can retrieve a list of announced gopher
  2889.      links?  I'd like to keep a local, up-to-date list of available gopher
  2890.      holes without requiring our users to gopher to umn just to scan
  2891.      GopherSpace.
  2892.  
  2893. A23: In the Unix client/server distribution is a perl script called
  2894.      "gopherdist". Gopherdist can fetch the contents of any point in
  2895.      GopherSpace.
  2896.  
  2897.      To dump the contents of all the North American links from
  2898.      gopher.tc.umn.edu do the following:
  2899.  
  2900.      % gopherdist gopher.tc.umn.edu 70 "1/Other Gopher and Information
  2901.        Servers/North America" > .Links
  2902. -------------------------------------------------------------------
  2903. Q24: Why doesn't my unix gopher client display ISO-Latin-1 characters
  2904.      properly?  BTW I'm using a Sun workstation..
  2905.  
  2906. A24: It is the client's problem, the server is perfectly 8-bit transparent.
  2907.      The BSD curses library uses bit 8 in order to remember, whether a
  2908.      character has been displayed reverse. So use just /usr/5bin/cc and
  2909.      you get the System V curses version which is 8 bit clean.
  2910.  
  2911.      Note that this may be a problem under other versions of UNIX too...
  2912.  
  2913. -------------------------------------------------------------------
  2914. Q25: What is veronica?
  2915.  
  2916. A25: veronica:  Very Easy Rodent-Oriented Net-wide Index to
  2917.      Computerized Archives.
  2918.  
  2919.      veronica offers a keyword search of most gopher-server menu titles
  2920.      in the entire gopher web.  As archie is to ftp archives, veronica
  2921.      is to gopherspace.  A veronica search produces a menu of gopher
  2922.      items, each of which is a direct pointer to a gopher data source.
  2923.      Because veronica is accessed through a gopher client, it is easy
  2924.      to use, and gives access to all types of data supported by the
  2925.      gopher protocol.
  2926.  
  2927.      To try veronica, select it from the "Other Gophers" menu on
  2928.      Minnesota's gopher server, or point your gopher at:
  2929.  
  2930.      Name=veronica (search menu items in most of GopherSpace)
  2931.      Type=1
  2932.      Port=70
  2933.      Path=1/veronica
  2934.      Host=futique.scs.unr.edu
  2935. --
  2936.  | Paul Lindner | lindner@boombox.micro.umn.edu   | Slipping into madness
  2937.  |              | Computer & Information Services | is good for the sake
  2938.  | Gophermaster | University of Minnesota         | of comparison.
  2939. ///// / / /    /////// / / / /  /  /  /   /      //// / / / /  /  /  /   /
  2940. ./ ENDUP
  2941. ?!
  2942. //CLIST    EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='CLIST'
  2943. //SYSIN    DD   DATA,DLM='?!'
  2944. ./ ADD NAME=NNMFIUCV
  2945. /* REXX.  This exec scans the job pack queues for IUCVMULT and returns
  2946.  * with an error code if IUCVMULT is already loaded under a
  2947.  * different TCB. This can only happen under PIE MultiTSO or a
  2948.  * similar product that makes multiple job step TCB's.
  2949.  */
  2950.  
  2951. trace off
  2952. signal on novalue
  2953.  
  2954. search_name = "IUCVMULT"
  2955. count = 0
  2956. foundtcb. = ""
  2957. current_tcb  = getword24("21C")
  2958. current_job_step_tcb = getword24(current_tcb,"7C")
  2959. current_ascb = getword24("224")
  2960. current_asxb = getword31(current_ascb,"6C")
  2961. first_tcb    = getword24(current_asxb,"4")
  2962. tcb = first_tcb
  2963. motherflag = 0
  2964. do forever
  2965.  if motherflag = 0 then do
  2966.   call process
  2967.   daughter_tcb = getword24(tcb,"88")
  2968.   if daughter_tcb \= "00000000" then do
  2969.    tcb = daughter_tcb
  2970.    iterate
  2971.   end
  2972.  end
  2973.  motherflag = 0
  2974.  sister_tcb = getword24(tcb, "80")
  2975.  if sister_tcb \= "00000000" then do
  2976.   tcb = sister_tcb
  2977.   iterate
  2978.  end
  2979.  mother_tcb = getword24(tcb, "84")
  2980.  if mother_tcb \= "00000000" then do
  2981.   tcb = mother_tcb
  2982.   motherflag = 1
  2983.   iterate
  2984.  end
  2985.  leave
  2986. end
  2987.  
  2988. if count = 0 then return 0
  2989. problem = 0
  2990. do i = 1 to count
  2991.  if foundtcb.i = current_job_step_tcb then do
  2992.   /*
  2993.   say search_name "is already loaded under current TCB at "foundtcb.i"."
  2994.   */
  2995.  end
  2996.  else do
  2997.   /*
  2998.   say search_name "is loaded under different TCB at "foundtcb.i"."
  2999.   */
  3000.   problem = 1
  3001.  end
  3002. end
  3003.  
  3004. if problem = 1 then return 1
  3005.  
  3006. else return 0
  3007.  
  3008. process:
  3009.  
  3010.  jpq = getword31(tcb,"2C")
  3011.  cde = jpq
  3012.  do while cde \= "00000000"
  3013.   cde_contents = storage(cde,32)
  3014.   cde_name = substr(cde_contents,9,8)
  3015.   cde_epa  = substr(cde_contents,9,8)
  3016.   if search_name = cde_name then do
  3017.    count = count + 1
  3018.    foundtcb.count = tcb
  3019.   end
  3020.   cde = getword31(cde,"0")
  3021.  end
  3022.  
  3023. return
  3024.  
  3025. getword31: parse arg addr, offset
  3026. temp1 = x2d(addr)
  3027. if offset = "" then temp2 = 0
  3028. else temp2 = x2d(offset)
  3029. return c2x(storage(d2x(temp1+temp2),4))
  3030.  
  3031. getword24: parse arg addr, offset
  3032. temp1 = x2d(addr)
  3033. if offset = "" then temp2 = 0
  3034. else temp2 = x2d(offset)
  3035. return "00"c2x(storage(d2x(temp1+temp2+1),3))
  3036.  
  3037. ./ ADD NAME=GOPHER
  3038. /* REXX. GOPHER client.  Author: Steve Bacher <seb@draper.com>, with
  3039.  *       additions by Dwight Cook <SYSDC@uokmvsa.backbone.uoknor.edu>
  3040.  */
  3041.  
  3042. /* *** Customize the following lines for your installation.
  3043.  * If ggmpanel is set to "", it will not be LIBDEF'd.
  3044.  */
  3045.  
  3046. ggmprefix        = "GOPHER"
  3047. ggmpanelsuffix   = "PANELS"
  3048. ggmloadsuffix    = "LOAD"
  3049. ggmlmod          = "GGCLIENT"
  3050. ggmpanel         = ggmprefix"."ggmpanelsuffix
  3051. ggmload          = ggmprefix"."ggmloadsuffix
  3052. ggmappl          = "ISR"
  3053. ggmdefaulthost   = "micro.umn.edu" /* initialize GOPHERRC with this  */
  3054. ggmdefaulttelnet = "TELNET"
  3055. ggmdefaultdomain = ".DRAPER.COM"
  3056. gophermeister    = ""              /* TSOid of Gopher's Big Brother  */
  3057. xprocavailable   = 0               /* set to 1 if XPROC is available */
  3058. crunlibs         = ""              /* if C run-time must be LIBDEF'd */
  3059.  
  3060. trace off
  3061. signal on novalue
  3062. stacked   = 0
  3063. libdeffed = 0
  3064. parse arg args
  3065. "ISPQRY"
  3066. if rc > 0 then do
  3067.  parse source . . execname . execds .
  3068.  if execds = "?" then
  3069.   icmd = "%"execname args
  3070.  else
  3071.   icmd = "EX '"execds"("execname")'" quote(args)
  3072.  call startispf ggmappl, icmd
  3073.  exit
  3074. end
  3075.  
  3076. if xprocavailable then do
  3077.  
  3078.  save_prompt = prompt("ON")
  3079.  "XPROC 0 TEST DEBUG FORCE LOCAL
  3080.           BOOKMARK() SERVER() PORT() PATH() DESCRIPTION()"
  3081.  if rc <> 0 then exit rc
  3082.  call prompt save_prompt
  3083.  
  3084. end
  3085.  
  3086. else do /* XPROC not available */
  3087.  
  3088.  bookmark = ""
  3089.  server = ""
  3090.  port = 70
  3091.  path  =
  3092.  description =
  3093.  local =
  3094.  force =
  3095.  test  =
  3096.  debug =
  3097.  uargs = translate(args)
  3098.  if wordpos("LOCAL",uargs) > 0 then local = "LOCAL"
  3099.  if wordpos("FORCE",uargs) > 0 then force = "FORCE"
  3100.  if wordpos("TEST" ,uargs) > 0 then test  = "TEST"
  3101.  if wordpos("DEBUG",uargs) > 0 then debug = "DEBUG"
  3102.  
  3103.  /* Limited-function parsing courtesy Dwight Cook */
  3104.  
  3105.  bookopen = 'BOOKMARK('
  3106.  servopen = 'SERVER('
  3107.  pathopen = 'PATH('
  3108.  portopen = 'PORT('
  3109.  descopen = 'DESCRIPTION('
  3110.  closparn = ')'
  3111.  parse var uargs (bookopen) bookmark    (closparn)
  3112.  parse var uargs (servopen) server      (closparn)
  3113.  parse var uargs (pathopen) path        (closparn)
  3114.  parse var uargs (portopen) port        (closparn)
  3115.  parse var uargs (descopen) description (closparn)
  3116.  if port = "" then port = 70
  3117.  
  3118. end
  3119.  
  3120. signal on failure
  3121. signal on halt
  3122.  
  3123. call check_for_other_socket_app
  3124. call read_gopherrc
  3125. call validate_operands
  3126. call libdef
  3127. call let_me_know
  3128. call ggm_dialog
  3129. call unlibdef
  3130.  
  3131. cleanup:
  3132. if libdeffed then call unlibdef
  3133. if stacked then "DELSTACK"
  3134. exit
  3135. error:failure:halt:say "GOPHER: Severe lossage."
  3136. say "Statement:" sourceline(sigl)
  3137. exit
  3138.  
  3139. /*********************************************************************/
  3140.  
  3141. validate_operands:
  3142.  
  3143. /*
  3144.  * Logic that determines what to display on startup:
  3145.  * If gopherrc file does not exist, create it from default
  3146.  * (default has everything commented out except for a
  3147.  *  one-item "initial" menu pointing to the MVS server)
  3148.  * Read gopherrc (in case operands need fields therein)
  3149.  * Command operands override gopherrc specs:
  3150.  * if LOCAL given then server = "-", see below for SERVER(-)
  3151.  * if SERVER(host) given then startup host=SERVER, path=PATH, etc.
  3152.  *  (no gopherrc referenced)
  3153.  * if SERVER(-) given then either PATH must be given or
  3154.  *  the gopherrc's localmenu: must be given,
  3155.  *  otherwise look at gopherrc
  3156.  *   if LOCAL given and initial: present then extract startup menu
  3157.  *    but remember that there will be no server access possible
  3158.  *   else nothing given, this is an error, barf
  3159.  * if no SERVER, look at gopherrc:
  3160.  *   if initial: given then extract startup menu from there
  3161.  *   else if localmenu: given then use that menu (SERVER=-)
  3162.  *   else nothing given, display ISPF panel asking for host/path
  3163.  */
  3164.  
  3165. if local = "LOCAL" then do
  3166.  if server <> "" then do
  3167.   say "GOPHER: SERVER cannot be specified when LOCAL is specified."
  3168.   exit 12
  3169.  end
  3170.  server = "-"
  3171. end
  3172.  
  3173. if bookmark <> "" then do
  3174.  if server <> "" & local = "" then do
  3175.   say "GOPHER: SERVER cannot be specified when BOOKMARK is specified."
  3176.   exit 12
  3177.  end
  3178.  if path <> "" then do
  3179.   say "GOPHER: PATH cannot be specified when BOOKMARK is specified."
  3180.   exit 12
  3181.  end
  3182.  server = "-"
  3183.  if left(bookmark,1) = "'" then path = strip(bookmark,"B","'")
  3184.  else do
  3185.   tsoprefix = sysvar("SYSPREF")
  3186.   if tsoprefix = "" then path = bookmark
  3187.   else path = tsoprefix"."bookmark
  3188.  end
  3189.  if description = "" then description = "Bookmark" path
  3190. end
  3191.  
  3192. ggpath = ""
  3193. gghost = ""
  3194. ggport = port
  3195. ggdesc = description
  3196.  
  3197. if server <> "" then do
  3198.  if server = "-" then do
  3199.   gghost = server
  3200.   if path <> "" then do
  3201.    ggpath = path
  3202.   end
  3203.   else if localmenu <> "" then do
  3204.    ggpath = localmenu
  3205.    if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  3206.   end
  3207.   else if local = "LOCAL" & initial <> "" then do
  3208.    gghost = ""
  3209.    call use_initial_spec
  3210.    if gghost <> "-" then do
  3211.     say "Gopher: Cannot determine path for local access."
  3212.     say "        Either specify PATH(pathname), activate"
  3213.     say "        the localmenu: line in GOPHERRC, or set"
  3214.     say "        the initial: line in GOPHERRC for local access."
  3215.     exit 12
  3216.    end
  3217.   end
  3218.   else do
  3219.    say "Gopher: Cannot determine path for local access."
  3220.    say "        Either specify PATH(pathname) or activate"
  3221.    say "        the localmenu: or initial: line in GOPHERRC."
  3222.    exit 12
  3223.   end
  3224.  end
  3225.  else do
  3226.   gghost = server
  3227.   ggpath = path
  3228.   ggdesc = description
  3229.   ggport = port
  3230.   nop  /* use provided server, host, path, etc. */
  3231.  end
  3232. end
  3233. else do       /* no server given on command */
  3234.  if localmenu <> "" then do
  3235.   gghost = "-"
  3236.   ggpath = localmenu
  3237.   if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  3238.  end
  3239.  else if initial <> "" then do
  3240.   call use_initial_spec
  3241.  end
  3242.  else do
  3243.   /* this is nominally illegal, but should cause gopher to
  3244.      display the hackish startup menu */
  3245.   gghost = ""
  3246.   ggpath = ""
  3247.  end
  3248. end
  3249.  
  3250. if telnet = "" then ggtelnet = ggmdefaulttelnet
  3251. else ggtelnet = telnet
  3252.  
  3253. if domain = "" then ggdomain = ggmdefaultdomain
  3254. else ggdomain = domain
  3255.  
  3256. return
  3257.  
  3258. /*********************************************************************/
  3259.  
  3260. use_initial_spec:
  3261.  
  3262.  if initial = "*temp*" then do
  3263.   /* we're eventually not going to do it this way really */
  3264.   /* initial_type is ignored - only "DIRECTORY" is valid anyway */
  3265.   if initial_name <> "" & ggdesc = "" then ggdesc = initial_name
  3266.   if initial_host <> "" & gghost = "" then gghost = initial_host
  3267.   if initial_path <> "" & ggpath = "" then ggpath = initial_path
  3268.   if initial_port <> "" & ggport = "" then ggport = initial_port
  3269.  end
  3270.  else do
  3271.   ggpath = initial
  3272.   if ggdesc = "" then ggdesc = "Local Private Gopher Menu"
  3273.  end
  3274.  
  3275. return
  3276.  
  3277. /*********************************************************************/
  3278.  
  3279. read_gopherrc:
  3280.  
  3281. localmenu = ""
  3282. localexec = ""
  3283. telnet    = ""
  3284. domain    = ""
  3285. initial   = ""
  3286. initial_type = ""
  3287. initial_name = ""
  3288. initial_host = ""
  3289. initial_path = ""
  3290. initial_port = ""
  3291. new_gopherrc = 0
  3292. gopherrc = "'"userid()".GOPHERRC'"
  3293. gopherdcb = "RECFM(V B) LRECL(255) BLKSIZE(6233) DSORG(PS)"
  3294. gopherrc_status = sysdsn(gopherrc)
  3295. select
  3296.  when gopherrc_status = "OK" then nop
  3297.  when gopherrc_status = "DATASET NOT FOUND" then do
  3298.   address TSO "ALLOC DA("gopherrc") T SP(1 1)" gopherdcb
  3299.   if rc <> 0 then do
  3300.    say "Error: Cannot create" gopherrc
  3301.    exit rc
  3302.   end
  3303.   new_gopherrc = 1
  3304.  end
  3305.  otherwise do
  3306.   say "Error: Cannot access" gopherrc":" gopherrc_status
  3307.   exit 16
  3308.  end
  3309. end
  3310.  
  3311. address TSO "ALLOC FI(GOPHERRC) DA("gopherrc") OLD REU"
  3312. if rc <> 0 then exit rc
  3313.  
  3314. if new_gopherrc = 0 then do
  3315.  "EXECIO * DISKR GOPHERRC (FINIS STEM GOPHERRC.)"
  3316.  execiorc = rc
  3317.  if execiorc <> 0 then do
  3318.   say "Error: Cannot read" gopherrc
  3319.   address TSO "FREE FI(GOPHERRC)"
  3320.   exit execiorc
  3321.  end
  3322.  if gopherrc.0 = 0 then new_gopherrc = 1
  3323. end
  3324.  
  3325. if new_gopherrc then call initialize_gopherrc
  3326.  
  3327. address TSO "FREE FI(GOPHERRC)"
  3328.  
  3329. collecting_initial = 0
  3330. do i = 1 to gopherrc.0
  3331.  gline = gopherrc.i
  3332.  if gline = "" then iterate
  3333.  if left(gline,1) = '#' then iterate
  3334.  parse var gline ghead ":" gtext
  3335.  ghead = translate(strip(ghead,"B"))
  3336.  gtext = strip(gtext,"B")
  3337.  if collecting_initial then do
  3338.   parse var gline ghead "=" gtext
  3339.   ghead = translate(strip(ghead,"B"))
  3340.   gtext = strip(gtext,"B")
  3341.   select
  3342.    when ghead = "TYPE" then initial_type = gtext
  3343.    when ghead = "NAME" then initial_name = gtext
  3344.    when ghead = "PATH" then initial_path = gtext
  3345.    when ghead = "HOST" then initial_host = gtext
  3346.    when ghead = "PORT" then initial_port = gtext
  3347.    when ghead = "END"  then do
  3348.     collecting_initial = 0
  3349.     initial = "*temp*"
  3350.    end
  3351.    otherwise do
  3352.     say "Error in "gopherrc": INITIAL: not terminated by END"
  3353.     say "Line where error was detected:"
  3354.     say gline
  3355.     exit 8
  3356.    end
  3357.   end
  3358.  end
  3359.  else select
  3360.   when ghead = "LOCALMENU" then localmenu = gtext
  3361.   when ghead = "LOCALEXEC" then localexec = gtext
  3362.   when ghead = "TELNET"    then telnet    = gtext
  3363.   when ghead = "DOMAIN"    then domain    = gtext
  3364.   when ghead = "INITIAL"   then do
  3365.    if gtext = "" then collecting_initial = 1
  3366.    else initial = gtext
  3367.   end
  3368.   otherwise do
  3369.    say "Warning, gopherrc field ignored:" ghead
  3370.   end
  3371.  end
  3372. end
  3373.  
  3374. return
  3375.  
  3376. /*********************************************************************/
  3377.  
  3378. ggm_dialog:
  3379.  
  3380. vputvars = "GGHOST GGPORT GGPATH GGDESC GGDOMAIN GGTELNET"
  3381.  
  3382. if vputvars <> "" then do
  3383.  address ISPEXEC "VPUT ("vputvars") PROFILE"
  3384.  if rc <> 0 then do; call ispf_error rc; exit rc; end
  3385. end
  3386.  
  3387. parm = ""
  3388. if test  = "TEST"  then parm = parm "-t"
  3389. if debug = "DEBUG" then parm = parm "-d"
  3390. if local = "LOCAL" then parm = parm "-l"
  3391. if gghost <> ""    then parm = parm "-q"
  3392.  
  3393. zerrmsg = ""
  3394. zerrsm  = ""
  3395. zerrlm  = ""
  3396.  
  3397. address ISPEXEC "VPUT (ZERRMSG ZERRSM ZERRLM)"
  3398.  
  3399. if ggmappl = "" then applsource = ""
  3400. else applsource = "NEWAPPL("ggmappl") PASSLIB"
  3401.  
  3402. if ggmload = "" then selstring = "PGM("ggmlmod") PARM("parm")"
  3403. else selstring = "CMD(CALL '"ggmload"("ggmlmod")'" quote(parm)")"
  3404.  
  3405. address ISPEXEC "SELECT" applsource selstring
  3406.  
  3407. if rc <> 0 then say "Return code from" ggmlmod "program is" rc
  3408.  
  3409. address ISPEXEC "VGET (ZERRSM ZERRLM)"
  3410. if zerrsm <> "" then do
  3411.  say zerrmsg":" zerrsm
  3412.  say zerrlm
  3413. end
  3414.  
  3415. return
  3416.  
  3417. /*********************************************************************/
  3418.  
  3419. libdef:
  3420. if crunlibs <> "" then do
  3421.  address ISPEXEC "LIBDEF ISPLLIB DATASET ID("crunlibs")"
  3422.  if rc <> 0 then do; call ispf_error rc; exit rc; end
  3423. end
  3424. if ggmpanel <> "" then do
  3425.  address ISPEXEC "LIBDEF ISPPLIB DATASET ID('"ggmpanel"')"
  3426.  if rc <> 0 then do; call ispf_error rc; exit rc; end
  3427. end
  3428. if localexec <> "" then do
  3429.  address TSO "ALLOC FI(GGEXEC) SHR REU DA('"localexec"')"
  3430.  if rc <> 0 then exit rc
  3431. end
  3432. libdeffed = 1
  3433. return
  3434.  
  3435. /*********************************************************************/
  3436.  
  3437. unlibdef:
  3438. if localexec <> "" then do
  3439.  address TSO "FREE FI(GGEXEC)"
  3440. end
  3441. if ggmpanel <> "" then do
  3442.  address ISPEXEC "LIBDEF ISPPLIB DATASET"
  3443.  if rc <> 0 then call ispf_error rc
  3444. end
  3445. if crunlibs <> "" then do
  3446.  address ISPEXEC "LIBDEF ISPLLIB DATASET"
  3447.  if rc <> 0 then call ispf_error rc
  3448. end
  3449. libdeffed = 0
  3450. return
  3451.  
  3452. /*********************************************************************/
  3453.  
  3454. initialize_gopherrc:
  3455.  
  3456.  say "Initializing new GOPHERRC file..."
  3457.  do i = sigl while sourceline(i) <> "_BEGIN_"
  3458.  end
  3459.  gx = 0
  3460.  do i = i+1 by 1
  3461.   gline = sourceline(i)
  3462.   if gline = "_END_" then leave
  3463.   gpos = pos("ggmdefaulthost",gline)
  3464.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaulthost
  3465.   gpos = pos("ggmdefaulttelnet",gline)
  3466.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaulttelnet
  3467.   gpos = pos("ggmdefaultdomain",gline)
  3468.   if gpos > 0 then gline = substr(gline,1,gpos-1) || ggmdefaultdomain
  3469.   gx = gx + 1
  3470.   gopherrc.gx = gline
  3471.  end
  3472.  gopherrc.0 = gx
  3473.  "EXECIO * DISKW GOPHERRC (FINIS STEM GOPHERRC.)"
  3474.  say "New GOPHERRC file initialized."
  3475.  
  3476. return
  3477.  
  3478. /*
  3479.  
  3480. _BEGIN_
  3481. #
  3482. #
  3483. # Default "gopherrc" file, created by the MVS Gopher client.
  3484. #
  3485. # Uncomment desired fields by removing the initial "# " from them.
  3486. #
  3487. # Beware - the Gopher client may update this file with bookmarks.
  3488. #          You can delete it at any time and it will be recreated
  3489. #          from the default settings, but you'll lose your bookmarks.
  3490. #
  3491. ######################################################################
  3492. #
  3493. # If you want local (serverless) gopher access, then use the following
  3494. # lines, specifying full qualified (no quotes) data set names:
  3495. #
  3496. # localmenu: name_of_initial_gopher_menu
  3497. # localexec: name_of_pds_of_rexx_execs
  3498. #
  3499. # Specifying localmenu: is equivalent to specifying an initial: section
  3500. # with host set to "-" and path set to the value of localmenu.
  3501. #
  3502. # You cannot use your own REXX execs, however, unless you specify
  3503. # localexec: as above.  You don't need one to use the other, though.
  3504. #
  3505. ######################################################################
  3506. #
  3507. # The following is used by the Gopher client at startup to determine
  3508. # how the initial menu will appear.
  3509. #
  3510. # You may want to change the host to the one appropriate for your site.
  3511. #
  3512. initial:
  3513. #
  3514. Type=DIRECTORY
  3515. Name=Primary (Root) Gopher Menu
  3516. Path=
  3517. Host=ggmdefaulthost
  3518. Port=70
  3519. End
  3520. #
  3521. # Alternatively, if you want your own private Gopher data:
  3522. #
  3523. # initial:
  3524. #
  3525. # Type=0
  3526. # Name=My Own Private Gopherhole
  3527. # Path=userid.GOPHER.MENU
  3528. # Host=-
  3529. # End
  3530. #
  3531. # In which case you should create a data set called userid.GOPHER.MENU
  3532. # (or whatever name you choose that appears in the "Path=" line above)
  3533. # that looks like this.  (NOT in the gopherrc file!)
  3534. #
  3535. #
  3536. # gopher_menu
  3537. #
  3538. # TYPE=DIRECTORY
  3539. # NAME=Public GOPHER Server at ggmdefaulthost
  3540. # PATH=
  3541. # HOST=ggmdefaulthost
  3542. # END
  3543. #
  3544. # TYPE=DIRECTORY
  3545. # NAME=Private GOPHER
  3546. # PATH=userid.ANOTHER.GOPHER.MENU
  3547. # HOST=-
  3548. # END
  3549. #
  3550. # and then you need yet another menu, similar in format to this one,
  3551. # in userid.ANOTHER.GOPHER.MENU.  Get the idea?
  3552. #
  3553. ######################################################################
  3554. #
  3555. # These fields are used by the Gopher client to set defaults.
  3556. #
  3557. Telnet: ggmdefaulttelnet
  3558. Domain: ggmdefaultdomain
  3559. #
  3560. ######################################################################
  3561. _END_
  3562.  
  3563. */
  3564.  
  3565. /*********************************************************************/
  3566.  
  3567. check_for_other_socket_app:
  3568.  
  3569.  if local = "LOCAL" then return
  3570.  
  3571.  call nnmfiucv      /* FIND IUCVMULT in another PIE MultiTSO session */
  3572.  
  3573.  if result = 0 then return
  3574.  
  3575.  say,
  3576.  "A TCP/IP socket application appears active in another PIE session."
  3577.  if force = "FORCE" then do
  3578.   say "Proceeding anyhow, because you said FORCE."
  3579.   return
  3580.  end
  3581.  say "To proceed at this point would be potentially disastrous."
  3582.  say "If you want to use GOPHER anyway, use one of these operands:"
  3583.  say "  FORCE  -  if I'm mistaken and it's really safe to make a"
  3584.  say "            TCP/IP connection."
  3585.  say "  LOCAL  -  if you just want local (serverless) access."
  3586.  say "Terminating."
  3587.  
  3588. exit 16
  3589.  
  3590. /*********************************************************************/
  3591.  
  3592. ispf_error: parse arg ispfrc
  3593.  
  3594. say "GOPHER: ISPF dialog service error detected on line" sigl
  3595. say sourceline(sigl)
  3596. say
  3597. say zerrmsg":" zerrsm
  3598. say zerrlm
  3599. say
  3600.  
  3601. return ispfrc
  3602.  
  3603. /*********************************************************************/
  3604.  
  3605. /*
  3606.  * The following function starts ISPF from READY mode.
  3607.  * Beware:  splitting the screen starts up an identical copy of the
  3608.  *          application, which may not be desirable.
  3609.  */
  3610.  
  3611. startispf: parse arg startappl, startcmd
  3612. if startappl = "" then,
  3613.  "ISPSTART CMD("startcmd")"
  3614. else,
  3615.  "ISPSTART NEWAPPL("startappl") CMD("startcmd")"
  3616. return
  3617.  
  3618. /* The following function implements Big Brother mode. */
  3619.  
  3620. let_me_know:
  3621. if gophermeister = "" | gophermeister = userid() then return
  3622. parse source . . execname . execds .
  3623. call outtrap "X."
  3624. address TSO,
  3625.  "SEND" quote(execds"("execname")" date("U") time()" "),
  3626.         "U("gophermeister") LOGON"
  3627. call outtrap "OFF"
  3628. return
  3629.  
  3630. /* The following function enquotes a string. */
  3631.  
  3632. quote: parse arg string
  3633. ix = 1
  3634. do forever
  3635.  ix = pos("'",string,ix)
  3636.  if ix = 0 then return "'"string"'"
  3637.  string = insert("'",string,ix)
  3638.  ix=ix+2
  3639. end
  3640.  
  3641. ./ ADD NAME=HOSTNAME
  3642. /* REXX */
  3643.  
  3644. return "MVS.DRAPER.COM"   /* or your hostname, in production */
  3645. /* return "-" */          /* for local private testing */
  3646.  
  3647. ./ ADD NAME=PORT
  3648. /* REXX */
  3649.  
  3650. /* Used by execs driven by the secondary gopher server running on
  3651.  * port 1570.  That's why the "70" line is commented out.
  3652.  */
  3653.  
  3654. /* return "70"               default for most gopher servers */
  3655.  
  3656. return "1570"             /* use secondary Gopher server */
  3657.  
  3658. ./ ADD NAME=TSOHELP
  3659. /* REXX */
  3660.  
  3661. /* This exec provides a sample TSO HELP application.
  3662.    The gopher menu item will look something like this:
  3663.  
  3664. TYPE=DIRECTORY
  3665. NAME=TSO HELP
  3666. PATH=EXEC:TSOHELP
  3667. HOST=+
  3668. END
  3669.  
  3670. where "TSOHELP" is the name of this exec.
  3671.  
  3672. This exec generates a series of lower-level menus, giving the user
  3673. a choice of how much help data to search (IBM only, local installation
  3674. help, etc.).  This particular sample is Draper Lab's own, so you will
  3675. need to change it.
  3676.  
  3677.  */
  3678.  
  3679. trace off
  3680. signal on novalue
  3681.  
  3682. host = hostname()
  3683. port = "70"
  3684. tab  = '05'x
  3685.  
  3686. helpfiles.        = "'SYS1.HELP'"
  3687. helpfiles.sys1    = "'SYS1.HELP'"
  3688. helpfiles.draper  = "'CSD.CMD.HELP' 'CSD.PP.HELP' 'SYS1.HELP'"
  3689. helpfiles.proglib = "'PROGLIB.CMD.HELP'"
  3690.  
  3691. parse arg helplib command type extra
  3692.  
  3693. if helplib = "" then,
  3694.      call display_top_menus
  3695. else call set_up_help helplib,command,type,extra
  3696.  
  3697. return 0
  3698.  
  3699. /*------------------------------------------------------------------*/
  3700.  
  3701. display_top_menus:
  3702.  
  3703.  call start_output
  3704.  call menu_out "SYS1",  "COMMANDS","DIRECTORY","Regular IBM TSO Help"
  3705.  call menu_out "DRAPER","COMMANDS","DIRECTORY","IBM and Draper TSO Help"
  3706.  call menu_out "PROGLIB","PROGLIB" ,"DIRECTORY","PROGLIB TSO Help"
  3707.  call end_output
  3708.  
  3709. return
  3710.  
  3711. /*------------------------------------------------------------------*/
  3712.  
  3713. set_up_help:  parse arg helplib,command,type,extra
  3714.  
  3715.  call outtrap "TSO."
  3716.  "ALLOC FI(SYSHELP) SHR REU DA("helpfiles.helplib")"
  3717.  allocrc = rc
  3718.  call outtrap "OFF"
  3719.  if allocrc <> 0 then do
  3720.   call start_output
  3721.   do i = 1 to tso.0
  3722.    call menu_out "ERROR","ERROR","DIRECTORY",tso.i
  3723.   end
  3724.   call end_output
  3725.  end
  3726.  else do
  3727.   select
  3728.    when type = "FILE"      then call specific_help command,extra
  3729.    when type = "DIRECTORY" then call general_help  command,extra
  3730.    when type = "INDEX"     then call index_help    extra
  3731.    otherwise                    call specific_help command
  3732.  end
  3733.  
  3734. return
  3735.  
  3736. /*------------------------------------------------------------------*/
  3737.  
  3738. index_help:
  3739.  
  3740.  /* This intermediate one-element directory is necessary because
  3741.   * the Gopher INDEX format only returns directories, not files.
  3742.   */
  3743.  
  3744.  parse upper arg commands
  3745.  call start_output
  3746.  do while commands <> ""
  3747.   parse var commands command commands
  3748.   call menu_out helplib,command,"FILE","Complete help for" command
  3749.   call menu_out helplib,command,"FILE","Function help only","FUNCTION"
  3750.   call menu_out helplib,command,"FILE","Syntax help only","SYNTAX"
  3751.   call menu_out helplib,command,"FILE","Operands help only","OPERANDS"
  3752.  end
  3753.  call end_output
  3754.  
  3755. return
  3756.  
  3757. /*------------------------------------------------------------------*/
  3758.  
  3759. general_help:
  3760.  
  3761. parse arg command,extra
  3762.  
  3763. call get_help_text command,extra
  3764.  
  3765. call start_output
  3766.  
  3767. call menu_out helplib,"*","INDEX","Help for a specific TSO command"
  3768.  
  3769. do i = 1 to help.0
  3770.  parse var help.i helpname helpdesc
  3771.  if helpdesc <> "" & ,
  3772.     length(helpname) <= 8 & ,
  3773.     helpname < "0" & ,
  3774.     verify(helpname,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789W#$") = 0 ,
  3775.     then do
  3776.  
  3777.   /*
  3778.    * Draper help has a series of "$..." members which are like
  3779.    * sublevel COMMANDS members.  This hack supports that.
  3780.    */
  3781.  
  3782.   if left(helpname,1) = "$" then do
  3783.    call menu_out helplib,helpname,"DIRECTORY",helpdesc
  3784.   end
  3785.   else do
  3786.    call menu_out helplib,helpname,"FILE",helpdesc
  3787.   end
  3788.  end
  3789. end
  3790.  
  3791. call end_output
  3792.  
  3793. return
  3794.  
  3795. /*------------------------------------------------------------------*/
  3796.  
  3797. specific_help:
  3798.  
  3799. parse arg command,extra
  3800.  
  3801. call get_help_text command,extra
  3802.  
  3803. call start_output
  3804.  
  3805. do i = 1 to help.0
  3806.  call text_output help.i
  3807. end
  3808.  
  3809. call end_output
  3810.  
  3811. return
  3812.  
  3813. /*------------------------------------------------------------------*/
  3814.  
  3815. get_help_text:
  3816.  
  3817. parse arg helpcmd,helpargs
  3818.  
  3819. help. =
  3820.  
  3821. call outtrap "HELP."
  3822.  
  3823. address TSO "HELP" helpcmd helpargs
  3824.  
  3825. call outtrap "OFF"
  3826.  
  3827. return
  3828.  
  3829. /*------------------------------------------------------------------*/
  3830.  
  3831. menu_out: parse arg mlib,mname,mtype,mdesc,mops
  3832.  
  3833.  select
  3834.   when mtype = "FILE"      then gtype = "0"
  3835.   when mtype = "DIRECTORY" then gtype = "1"
  3836.   when mtype = "INDEX"     then gtype = "7"
  3837.   otherwise do
  3838.    call menu_out "ERROR","ERROR","DIRECTORY", "Unknown type:" mtype
  3839.   end
  3840.  end
  3841.  
  3842.  gname = left(mname,9)"--" mdesc
  3843.  gpath = "EXEC:TSOHELP" mlib mname mtype mops
  3844.  out = gtype || gname || tab || gpath || tab || host || tab || port
  3845.  queue out
  3846.  
  3847. return
  3848.  
  3849. /*------------------------------------------------------------------*/
  3850.  
  3851. text_output: parse arg text
  3852.  
  3853.  if text = "" then queue " "
  3854.  else queue text
  3855.  
  3856. return
  3857.  
  3858. /*------------------------------------------------------------------*/
  3859.  
  3860. start_output:
  3861.  
  3862. "newstack"
  3863.  
  3864. return
  3865.  
  3866. /*------------------------------------------------------------------*/
  3867.  
  3868. end_output:
  3869.  
  3870. queue ""
  3871.  
  3872. "EXECIO * DISKW SYSTSPRT (FINIS)"
  3873.  
  3874. "delstack"
  3875.  
  3876. return
  3877.  
  3878. ./ ENDUP
  3879. ?!
  3880. //H        EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='H'
  3881. //SYSIN    DD   DATA,DLM='?!'
  3882. ./ ADD NAME=GG
  3883.  
  3884.  /********************************************************************/
  3885.  /*                                                                  */
  3886.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  3887.  /*                                                                  */
  3888.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  3889.  /*                                                                  */
  3890.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  3891.  /* including the implied warranties of merchantability and fitness, */
  3892.  /* are expressly denied.                                            */
  3893.  /*                                                                  */
  3894.  /* Provided this copyright notice is included, this software may    */
  3895.  /* be freely distributed and not offered for sale.                  */
  3896.  /*                                                                  */
  3897.  /* Changes or modifications may be made and used only by the maker  */
  3898.  /* of same, and not further distributed.  Such modifications should */
  3899.  /* be mailed to the author for consideration for addition to the    */
  3900.  /* software and incorporation in subsequent releases.               */
  3901.  /*                                                                  */
  3902.  /********************************************************************/
  3903.  
  3904. /* --------------------- "gg.h" include member --------------------- */
  3905.  
  3906. #pragma linkage(ispexec,OS)
  3907. #pragma linkage(isplink,OS)
  3908. #pragma linkage(ikjeff18,OS)
  3909.  
  3910. /****** Installation-customized defines. *****************************/
  3911.  
  3912. #include "gguser.h"
  3913.  
  3914. #ifndef  C370V1
  3915. #ifndef  C370V2
  3916. #ifndef  SASC
  3917.  install_error_neither_C370V1_C370V2_nor_SASC_was_defined;
  3918. #endif
  3919. #endif
  3920. #endif
  3921.  
  3922. #ifndef  TCPIPV1
  3923. #ifndef  TCPIPV2
  3924. #ifndef  SNSTCPIP
  3925.  install_error_neither_TCPIPV1_TCPIPV2_nor_SNSTCPIP_was_defined;
  3926. #endif
  3927. #endif
  3928. #endif
  3929.  
  3930. #ifndef  ISPFV2
  3931. #ifndef  ISPFV3
  3932.  install_error_neither_ISPFV2_nor_ISPFV3_was_defined;
  3933. #endif
  3934. #endif
  3935.  
  3936. #define  MVS
  3937.  
  3938. #ifdef  SNSTCPIP
  3939. #ifndef I370
  3940. #define SNSC370
  3941. #endif
  3942. #endif
  3943.  
  3944. /****** Clean up compiler warnings BEFORE time.h gets 'em ************/
  3945.  
  3946. #ifndef  SASC
  3947. #define  localtime            LOCALTIM
  3948. #endif
  3949.  
  3950. /****** Include all header files that are necessary. *****************/
  3951.  
  3952. #ifndef SNSTCPIP
  3953. #include <manifest.h>
  3954. #include <sys/types.h>
  3955. #include <netinet/in.h>
  3956. #include <sys/ioctl.h>
  3957. #include <tcperrno.h>
  3958. #include <fcntl.h>
  3959. #endif
  3960.  
  3961. #include <sys/socket.h>
  3962. #include <netdb.h>
  3963. #include <sys/uio.h>
  3964. #include <ctype.h>
  3965. #include <errno.h>
  3966. #include <limits.h>
  3967. #include <setjmp.h>
  3968. #include <stdio.h>
  3969. #include <stdarg.h>
  3970. #include <stdlib.h>
  3971. #include <string.h>
  3972. #include <stddef.h>
  3973. #include <time.h>
  3974.  
  3975. #ifdef SNSTCPIP
  3976. #include <acs.h>
  3977. #include <inet.h>
  3978. #include <sockcfg.h>
  3979. #include <serrno.h>
  3980. #endif
  3981.  
  3982. #ifndef  SASC
  3983. #include <ctest.h>
  3984. #endif
  3985.  
  3986. #ifdef   SASC
  3987. #include "ggsasc.h"
  3988. #endif
  3989.  
  3990. #undef ENOMEM
  3991.  
  3992. #include <mtf.h>
  3993.  
  3994. /****** Version-dependent stuff **************************************/
  3995.  
  3996. #ifdef   C370V1
  3997. #undef   FETCH
  3998. #endif
  3999.  
  4000. #ifdef   C370V2
  4001. #define  FETCH
  4002. #endif
  4003.  
  4004. #ifdef   TCPIPV1
  4005. #define  TCP_DEBUG            tcp_debug
  4006. #endif
  4007.  
  4008. #ifdef   TCPIPV2
  4009. #define  TCP_DEBUG            sock_debug
  4010. #endif
  4011.  
  4012. #ifdef   SNSTCPIP
  4013. #define  TCP_DEBUG            /* I don't know how to debug in SNS */
  4014. #undef   DEBUG
  4015. #endif
  4016.  
  4017. #ifdef   DEBUG
  4018. #define  TCP_DEBUG_ON         TCP_DEBUG(1)
  4019. #define  TCP_DEBUG_OFF        TCP_DEBUG(0)
  4020. #else
  4021. #define  TCP_DEBUG_ON         /* */
  4022. #define  TCP_DEBUG_OFF        /* */
  4023. #endif
  4024.  
  4025. /****** Preprocessor bookkeeping *************************************/
  4026.  
  4027. #define  Bool                 char
  4028. #define  Fool                 unsigned int /* for function arguments */
  4029. #ifndef  TRUE
  4030. #define  TRUE                 1
  4031. #endif
  4032. #ifndef  FALSE
  4033. #define  FALSE                0
  4034. #endif
  4035.  
  4036. #define  COMMANDSIZE          12
  4037.  
  4038. #define  GOPHER_FILE          '0'
  4039. #define  GOPHER_DIRECTORY     '1'
  4040. #define  GOPHER_CSO           '2'
  4041. #define  GOPHER_ERROR         '3'
  4042. #define  GOPHER_MAC_BINHEX    '4'
  4043. #define  GOPHER_DOS_BINARCH   '5'
  4044. #define  GOPHER_UUENCODE      '6'
  4045. #define  GOPHER_WAIS          '7'
  4046. #define  GOPHER_TELNET        '8'
  4047. #define  GOPHER_TN3270        'T'
  4048. #define  GOPHER_BINARY        '9'
  4049. #define  GOPHER_REDUNDANT     '+'
  4050. #define  GOPHER_WHOIS         'w'
  4051.  
  4052. #define  READ_BYTES           1024
  4053. #define  SERVER_BUF_MSGSIZE   1024
  4054. #define  CLIENT_BUF_MSGSIZE   1024
  4055. #define  TEXT_BYTES           1024
  4056. #define  INTERNET_SIZE        256
  4057. #define  RBUFSIZE             512
  4058. #define  OUTBUFSIZE           1024
  4059.  
  4060. #define  GOPHER_PORT_NUMBER   70
  4061. #define  GOPHER_HOST_LENGTH   MAXHOSTNAMELEN
  4062. #define  GOPHER_PATH_LENGTH   512
  4063. #define  GOPHER_DESC_LENGTH   256
  4064.  
  4065. #define  SOCKET_GETCHAR_ERROR (-1)
  4066. #define  SOCKET_NO_MORE       (-2)
  4067. #define  SOCKET_READ_NOTHING  (-3)
  4068.  
  4069. #define  NO_VALUE             (-1)
  4070.  
  4071. #define  Rstruc               register struct
  4072.  
  4073. #define  EQUAL                !strcmp
  4074. #define  UNEQUAL              strcmp
  4075. #define  COPY(A,B)            strncpy((A),(B),sizeof(A)-1)
  4076.  
  4077. #define  FIND_NEXT            'N'
  4078. #define  FIND_FIRST           'F'
  4079. #define  FIND_LAST            'L'
  4080. #define  FIND_PREV            'P'
  4081. #define  FIND_ALL             'A'
  4082. #define  FIND_CHARS           '\0'
  4083. #define  FIND_WORD            'W'
  4084. #define  FIND_PREFIX          'P'
  4085. #define  FIND_SUFFIX          'S'
  4086. #define  FIND_CAPS            '\0'
  4087. #define  FIND_ASIS            'A'
  4088. #define  FIND_HEX             'X'
  4089. #define  FIND_GENERIC         'P'
  4090. #define  FIND_BADFORM         '\0'
  4091. #define  FIND_UNQUOTED        'U'
  4092. #define  FIND_QUOTED          'Q'
  4093. #define  FIND_C               'C'
  4094. #define  FIND_X               'X'
  4095. #define  FIND_T               'T'
  4096. #define  FIND_P               'P'
  4097.  
  4098. #define  MAX_INT               (int)0x7fffffff
  4099. #define  LOCATE_INT            (int)0x7ffffffe
  4100.  
  4101. enum     scroll    {NO_SCROLL, UP, DOWN, LEFT, RIGHT, LOCATE};
  4102. enum     extreq    {EXTRACT_IT, PRINT_IT, BOOKMARK_IT};
  4103. enum     gohow     {AS_NORMAL, AS_FILE, AS_NOTHING};
  4104. enum     ostype    {DEFAULT_OS, VM_OS};
  4105.  
  4106. #define  CARRIAGE_RETURN      ('\r')
  4107.  
  4108. #ifdef   MVS
  4109. #ifdef   I370
  4110. #define  LINE_FEED            (0x15)
  4111. #else
  4112. #define  LINE_FEED            (0x25)
  4113. #endif
  4114. #else
  4115. #define  LINE_FEED            (0x0a)
  4116. #endif
  4117.  
  4118. #ifdef   MVS
  4119. #ifdef   I370
  4120. #define  EtoA                 htoncs
  4121. #define  AtoE                 ntohcs
  4122. #else
  4123. #ifdef   SNSTCPIP
  4124. #define  EtoA                 etoa
  4125. #define  AtoE                 atoe
  4126. #else
  4127. #define  EtoA(x)              ebcdictoascii[x]
  4128. #define  AtoE(x)              asciitoebcdic[x]
  4129. #define  ebcdictoascii        ebcdicto
  4130. #define  asciitoebcdic        asciitoe
  4131. #endif
  4132. #endif
  4133. #endif
  4134.  
  4135. #ifdef SNSC370
  4136. #define EBCDIC_TO_ASCII(A,B) EtoA(A,B)
  4137. #define ASCII_TO_EBCDIC(A,B) AtoE(A,B)
  4138. #else
  4139. #define EBCDIC_TO_ASCII(A,B) {int _i; \
  4140.                               for (_i=0; _i<(B); ++_i) \
  4141.                                   (A)[_i] = EtoA((A)[_i]); \
  4142.                              }
  4143. #define ASCII_TO_EBCDIC(A,B) {int _i; \
  4144.                               for (_i=0; _i<(B); ++_i) \
  4145.                                   (A)[_i] = AtoE((A)[_i]); \
  4146.                              }
  4147. #endif
  4148.  
  4149. #ifdef TCPIPV1
  4150. #define REPORT_TCP_ERROR(A)  /* */
  4151. #endif
  4152.  
  4153. #ifdef TCPIPV2
  4154. #define REPORT_TCP_ERROR(A)  tcperror(A)
  4155. #endif
  4156.  
  4157. #ifdef SNSTCPIP
  4158. #define REPORT_TCP_ERROR(A)  fprintf(stderr,\
  4159.                                     "\nTCP error on %s: errno = %d\n",\
  4160.                                     A,GET_ERRNO)
  4161. #endif
  4162.  
  4163. #ifdef SNSC370
  4164. #define Accept(A,B,C)        accept((A),(struct sockaddr *)(B),(C))
  4165. #define Bind(A,B,C)          bind((A),(struct sockaddr *)(B),(C))
  4166. #define Connect(A,B,C)       connect((A),(struct sockaddr *)(B),(C))
  4167. #define Gethostbyaddr(A,B,C) gethostbyaddr((char *)(A),(B),(C))
  4168. #define Getpeername(A,B,C)   getpeername((A),(struct sockaddr *)(B),(C))
  4169. #define Getsockname(A,B,C)   getsockname((A),(struct sockaddr *)(B),(C))
  4170. #define Getsockopt(A,B,C,D,E) getsockopt((A),(B),(C),(char *)(D),(E))
  4171. #define EWOULDBLOCK          (ESWOULDBLOCK+s0skcfg.errnobase)
  4172. #else
  4173. #define Accept               accept
  4174. #define Bind                 bind
  4175. #define Connect              connect
  4176. #define Gethostbyaddr        gethostbyaddr
  4177. #define Getpeername          getpeername
  4178. #define Getsockname(A,B,C)   getsockname((A),(char *)(B),(C))
  4179. #define Getsockopt           getsockopt
  4180. #endif
  4181.  
  4182. #ifdef   FETCH
  4183. #define  ISPLINK              (gp->isplink_pointer)
  4184. #define  ISPEXEC              (gp->ispexec_pointer)
  4185. #else
  4186. #define  ISPLINK              isplink
  4187. #define  ISPEXEC              ispexec
  4188. #endif
  4189.  
  4190. #define  DATAOUT_LOW          0x01
  4191. #define  DATAOUT_HIGH         0x02
  4192. #define  DATAIN_LOW           0x03
  4193. #define  DATAIN_HIGH          0x04
  4194. #define  DATAOUT_BLUE         DATAOUT_LOW
  4195. #define  DATAOUT_GREEN        0x05
  4196. #define  DATAOUT_PINK         0x06
  4197. #define  DATAOUT_RED          0x07
  4198. #define  DATAOUT_TURQ         0x08
  4199. #define  DATAOUT_WHITE        DATAOUT_HIGH
  4200. #define  DATAOUT_YELLOW       0x09
  4201. #define  DATAIN_BLUE          0x0a
  4202. #define  DATAIN_GREEN         DATAIN_LOW
  4203. #define  DATAIN_PINK          0x0b
  4204. #define  DATAIN_RED           DATAIN_HIGH
  4205. #define  DATAIN_TURQ          0x0c
  4206. #define  DATAIN_WHITE         0x0d
  4207. #define  DATAIN_YELLOW        0x0e
  4208.  
  4209. #define  S99VRBAL  0x01             /* ALLOCATION                    */
  4210. #define  S99VRBUN  0x02             /* UNALLOCATION                  */
  4211. #define  S99VRBCC  0x03             /* CONCATENATION                 */
  4212. #define  S99VRBDC  0x04             /* DECONCATENATION               */
  4213. #define  S99VRBRI  0x05             /* REMOVE IN-USE                 */
  4214. #define  S99VRBDN  0x06             /* DDNAME ALLOCATION             */
  4215. #define  S99VRBIN  0x07             /* INFORMATION RETRIEVAL         */
  4216. #define  S99NOCNV  0x40             /* ALLOC FUNCTION-DO NOT USE AN  */
  4217.                                     /* EXISTING ALLOCATION TO SATISFY*/
  4218.                                     /* THE REQUEST                   */
  4219. #define  DALDDNAM   0x0001          /* DDNAME                        */
  4220. #define  DALDSNAM   0x0002          /* DSNAME                        */
  4221. #define  DALMEMBR   0x0003          /* MEMBER NAME                   */
  4222. #define  DALSTATS   0x0004          /* DATA SET STATUS               */
  4223. #define  DALNDISP   0x0005          /* DATA SET DISPOSITION          */
  4224. #define  DALTRK     0x0007          /* TRACK SPACE TYPE              */
  4225. #define  DALBLKLN   0x0009          /* BLOCK LENGTH                  */
  4226. #define  DALPRIME   0x000a          /* PRIMARY SPACE ALLOCATION      */
  4227. #define  DALSECND   0x000b          /* SECONDARY SPACE ALLOCATION    */
  4228. #define  DALDIR     0x000c          /* DIRECTORY BLOCK ALLOCATION    */
  4229. #define  DALSYSOU   0x0018          /* SYSOUT                        */
  4230. #define  DALSFMNO   0x001a          /* SYSOUT FORMS NUMBER           */
  4231. #define  DALCOPYS   0x001d          /* SYSOUT COPIES                 */
  4232. #define  DALUCS     0x0029          /* UNIVERSAL CHARACTER SET       */
  4233. #define  DALBLKSZ   0x0030          /* DCB BLOCKSIZE                 */
  4234. #define  DALDSORG   0x003c          /* DATA SET ORGANIZATION         */
  4235. #define  DALLRECL   0x0042          /* DCB LOGICAL RECORD LENGTH     */
  4236. #define  DALRECFM   0x0049          /* DCB RECORD FORMAT             */
  4237. #define  DALPERMA   0x0052          /* PERMANENTLY ALLOCATED ATTRIB  */
  4238. #define  DALRTDDN   0x0055          /* RETURN DDNAME                 */
  4239. #define  DALRTDSN   0x0056          /* RETURN DSNAME                 */
  4240. #define  DALRTORG   0x0057          /* RETURN D.S. ORGANIZATION      */
  4241. #define  DALSUSER   0x0058          /* SYSOUT REMOTE WORKSTATION     */
  4242. #define  DUNDDNAM   0x0001          /* DDNAME                        */
  4243. #define  DUNDSNAM   0x0002          /* DSNAME                        */
  4244. #define  DUNUNALC   0x0007          /* UNALLOC OPTION                */
  4245.  
  4246. #define  SHR        0x08
  4247. #define  NEW        0x04
  4248. #define  MOD        0x02
  4249. #define  OLD        0x01
  4250. #define  KEEP       0x08
  4251. #define  DELETE     0x04
  4252. #define  CATLG      0x02
  4253. #define  UNCATLG    0x01
  4254. #define  RECFM_F    0x80
  4255. #define  RECFM_V    0x40
  4256. #define  RECFM_U    0xc0
  4257. #define  RECFM_D    0x20
  4258. #define  RECFM_T    0x20
  4259. #define  RECFM_B    0x10
  4260. #define  RECFM_S    0x08
  4261. #define  RECFM_A    0x04
  4262. #define  RECFM_M    0x02
  4263. #define  RECFM_FB   (RECFM_F | RECFM_B)
  4264. #define  RECFM_VB   (RECFM_V | RECFM_B)
  4265. #define  DSORG_PS   0x4000
  4266. #define  DSORG_PO   0x0200
  4267.  
  4268.  
  4269. /****** Data and structure definitions. ******************************/
  4270.  
  4271. typedef struct _textunit     TEXTUNIT;
  4272. typedef unsigned int         IPADDRESS;
  4273. typedef int                  SOCKETNO;
  4274. typedef char                 gophertype;
  4275. typedef enum     scroll      SCROLL;
  4276. typedef enum     extreq      EXTREQ;
  4277. typedef enum     gohow       GOHOW;
  4278. typedef enum     ostype      OSTYPE;
  4279.  
  4280. enum socket_retval  {
  4281.                      SERVER_READ_OK,
  4282.                      SERVER_READ_ERROR,
  4283.                      SERVER_BUFFER_ERROR,
  4284.                      SERVER_NO_MORE,
  4285.                      SERVER_READ_NOTHING
  4286.                     };
  4287.  
  4288. enum data_set_type  {
  4289.                      PDS,
  4290.                      SEQ,
  4291.                      UNK,
  4292.                      JES
  4293.                     };
  4294.  
  4295. enum user_option    {
  4296.                      OPTION_ALL,
  4297.                      OPTION_VIEW,
  4298.                      OPTION_OTHER
  4299.                     };
  4300.  
  4301. struct textline    {
  4302.                     struct textline    *next;
  4303.                     short               text_length;
  4304.                     short               tab_expanded_text_length;
  4305.                     char               *tab_expanded_text;
  4306.                     char                text[1];  /* dummy */
  4307.                    };
  4308.  
  4309. struct texthdr     {
  4310.                     int                   text_line_count;
  4311.                     struct textline      *text_body_line;
  4312.                     short                 text_max_length;
  4313.                     short                 text_max_tab_expanded_length;
  4314.                     struct textline      *first_text_line;
  4315.                     struct textline      *current_text_line;
  4316.                     struct textline      *last_text_line;
  4317.                    };
  4318.  
  4319. struct cmddesc   {
  4320.                   char    command_name[COMMANDSIZE];
  4321.                   Bool    (*command_processor)();
  4322.                  };
  4323.  
  4324. struct seldesc   {
  4325.                   char    selection_code;
  4326.                   Bool    (*selection_processor)();
  4327.                  };
  4328.  
  4329. struct tabledesc {
  4330.                   char   *command_variable;
  4331.         struct cmddesc   *first_cmddesc;
  4332.         struct seldesc   *first_seldesc;
  4333.                  };
  4334.  
  4335. struct _textunit {
  4336.                   unsigned short         key;
  4337.                   unsigned short         num;
  4338.                   struct {
  4339.                           unsigned short len;
  4340.                           char           prm[80];
  4341.                          }               ent;
  4342.                  };
  4343.  
  4344. struct extraction {
  4345.                    int                   from_number;
  4346.                    int                   to_number;
  4347.                    int                   count;
  4348.                    enum data_set_type    mode;
  4349.                    void                (*closer)();
  4350.                    Bool                  appending;
  4351.                    Bool                  blanking;
  4352.                    Bool                  tab_expanding;
  4353.                    EXTREQ                ex;
  4354.                    char                  panelname     [9];
  4355.                    char                  dsname       [65];
  4356.                    char                  separator    [81];
  4357.                    char                  member_prefix [9];
  4358.                    char                  ddname        [9];
  4359.                    char                  member        [9];
  4360.                   };
  4361.  
  4362. struct gopherinfo {
  4363.                    gophertype            type;
  4364.                    int                   port;
  4365.                    struct texthdr        thdr;
  4366.                    char                  path [GOPHER_PATH_LENGTH+1];
  4367.                    char                  host [GOPHER_HOST_LENGTH+1];
  4368.                    char                  desc [GOPHER_DESC_LENGTH+1];
  4369.                    char                  bmds [65]; /* bookmark file */
  4370.                   };
  4371.  
  4372. struct recvstruct {
  4373.     int             sockfd;   /* socket descriptor for socket call */
  4374.     int             outlen;
  4375.     int             myport;
  4376.     FILE           *outfp;    /* used by local (non-socket) interface*/
  4377.     FILE           *readfile;                 /* declare the file... */
  4378.     char           *fileptr;
  4379.     char           *wargptr;
  4380.     char           *mytelnet;
  4381.     char           *mydomain;
  4382.     struct hostent  clienthostent;
  4383.     char            myname  [MAXHOSTNAMELEN+1];
  4384.     char            hostname[MAXHOSTNAMELEN+1];  /* client host name */
  4385.     char            hosttest[MAXHOSTNAMELEN+1];  /* client host name */
  4386.     char            buffer  [RBUFSIZE]; /* client's character string */
  4387.     char            dsname  [RBUFSIZE];
  4388.     char            sockbuf [OUTBUFSIZE];    /* socket output buffer */
  4389.    };
  4390.  
  4391. struct menuitem {
  4392.     char          type;                  /* type of record to send   */
  4393.     char          desc     [GOPHER_DESC_LENGTH+1];
  4394.     char          select   [GOPHER_PATH_LENGTH+1];
  4395.     char          hostname [GOPHER_HOST_LENGTH+1];
  4396.     int           port;                  /* host port to connect to  */
  4397.    };
  4398.  
  4399. struct connection  {
  4400.              char   *server_buf;
  4401.              char   *client_buf;
  4402.               int    mybufl;
  4403.               int    nbytes;
  4404.               int    ibuflen;
  4405.               int    bytes_returned;
  4406.               int    buf_index;
  4407.          SOCKETNO    ns;
  4408.              Bool    time_to_go_home;
  4409.              Bool    server_has_something_pending;
  4410.              Bool    server_finished_replying;
  4411.              Bool    sending_text;
  4412.              Bool    receiving_text;
  4413.              Bool    dont_read;
  4414.              Bool    connected_to_server;
  4415.              Bool    connection_broken;
  4416.              Bool    closing_connection;
  4417.              Bool    is_ftp;
  4418.              char    server_hostname [MAXHOSTNAMELEN+1];
  4419.              char    buf [READ_BYTES];
  4420.                    };
  4421.  
  4422. struct Ftp        {
  4423.                    FILE                 *outfp;
  4424.                    FILE                 *errfp;
  4425.                    char                 *myname;
  4426.                    struct hostent       *server_hostent;
  4427.                    struct hostent       *client_hostent;
  4428.                    int                   backlog;
  4429.                    int                   myport;
  4430.                    SOCKETNO              listensocket;
  4431.                    Bool                  verboseflag;
  4432.                    Bool                  replaceflag;
  4433.                    Bool                  listflag;
  4434.                    Bool                  nlstflag;
  4435.                    Bool                  control_socket_opened;
  4436.                    Bool                  listen_socket_opened;
  4437.                    Bool                  accept_socket_opened;
  4438.                    gophertype            type;
  4439.                    OSTYPE                os;
  4440.                    IPADDRESS             hostaddress;
  4441.                    struct connection     control_connection;
  4442.                    struct connection     data_connection;
  4443.                    struct sockaddr_in    bindsock;
  4444.                    struct sockaddr_in    consock;
  4445.                    char                  ftphack [16];
  4446.                    char                  host [257];
  4447.                    char                  user [257];
  4448.                    char                  pass [257];
  4449.                    char                  path [257];
  4450.                    char                  client_hostname [257];
  4451.                    char                  server_hostname [257];
  4452.                   };
  4453.  
  4454. struct ggcb {
  4455.              char    *gopher_command;
  4456.              char    *extract_separator_line;
  4457.              char    *mytelnet;
  4458.              char    *mydomain;
  4459.              FILE    *debug_file;
  4460.              FILE    *extract_file;
  4461.   struct recvstruct  *recvp;
  4462.   struct extraction  *extractionp;
  4463.   struct gopherinfo  *ginfo;
  4464. #ifdef FETCH
  4465.               int   (*isplink_pointer)();
  4466.               int   (*ispexec_pointer)();
  4467. #endif
  4468.               int     ispfrc;
  4469.               int     text_find_left_bound;
  4470.               int     text_find_right_bound;
  4471.               int     myport;
  4472.              Bool     test_mode;
  4473.              Bool     debug_mode;
  4474.              Bool     quit;
  4475.              Bool     local_mode;
  4476.              Bool     extract_tab_expanding;
  4477.              Bool     extract_appending;
  4478.              Bool     extract_blank_before_separator;
  4479.              Bool     extract_write_error;
  4480.              Bool     extract_close_error;
  4481.              Bool     warn_overwrite;
  4482.              Bool     warn_append;
  4483.              Bool     setmsg;
  4484.              Bool     autoscroll;
  4485.              Bool     autocursor;
  4486.              Bool     setcursor;
  4487.              Bool     printing;
  4488.         IPADDRESS     client_ip_address;
  4489.         IPADDRESS     server_ip_address;
  4490.    struct texthdr     thdr;
  4491.    struct connection  gopher_connection;
  4492.              char     client_ip_addrstr   [16];
  4493.              char     server_ip_addrstr   [16];
  4494.              char     ggserver            [MAXHOSTNAMELEN+1];
  4495.              char     ggclient            [MAXHOSTNAMELEN+1];
  4496.              char     client_hostname     [MAXHOSTNAMELEN+1];
  4497.              char     server_hostname     [MAXHOSTNAMELEN+1];
  4498.              char     text_find_string    [81];
  4499.              char     text_dispchar;
  4500.              char     text_find_what;
  4501.              char     text_find_type;
  4502.              char     text_find_trans;
  4503.              char     current_bookmark_ds [65];
  4504.             };
  4505.  
  4506. #ifdef MVS
  4507. #ifndef I370
  4508. extern char                 ebcdictoascii[];
  4509. extern char                 asciitoebcdic[];
  4510. #endif
  4511. #endif
  4512.  
  4513. #ifndef FETCH
  4514. extern int                  isplink();
  4515. extern int                  ispexec();
  4516. #endif
  4517.  
  4518. #ifdef   ISPFV3
  4519. #define  ZERRLM_SIZE          513
  4520. #else
  4521. #define  ZERRLM_SIZE          73
  4522. #endif
  4523.  
  4524. #define  NOTIFY_MSG   1
  4525. #define  WARNING_MSG  2
  4526. #define  CRITICAL_MSG 3
  4527.  
  4528. #define  WARN1(X)           GGMpmsg(gp,NOTIFY_MSG,NULL,X)
  4529. #define  WARN2(X,Y)         GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y)
  4530. #define  WARN3(X,Y,Z)       GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z)
  4531. #define  WARN4(X,Y,Z,W)     GGMpmsg(gp,NOTIFY_MSG,NULL,X,Y,Z,W)
  4532. #define  ERR1(X)            GGMpmsg(gp,WARNING_MSG,NULL,X)
  4533. #define  ERR2(X,Y)          GGMpmsg(gp,WARNING_MSG,NULL,X,Y)
  4534. #define  ERR3(X,Y,Z)        GGMpmsg(gp,WARNING_MSG,NULL,X,Y,Z)
  4535. #define  ERR4(X,Y,Z,W)      GGMpmsg(gp,WARNING_MSG,NULL,X,Y,Z,W)
  4536. #define  CRIT1(X)           GGMpmsg(gp,CRITICAL_MSG,NULL,X)
  4537. #define  CRIT2(X,Y)         GGMpmsg(gp,CRITICAL_MSG,NULL,X,Y)
  4538. #define  CRIT3(X,Y,Z)       GGMpmsg(gp,CRITICAL_MSG,NULL,X,Y,Z)
  4539.  
  4540. #define  GETMAIN(Ptr,Typ,Siz,For) \
  4541.          GGMgetm(gp,(char **)&(Ptr),(sizeof(Typ))*(Siz),For)
  4542.  
  4543. #define  FREEMAIN(Ptr,For)    if (Ptr) {GGMfreem(gp,(char *)Ptr,For);}
  4544.  
  4545. #define  GOPHERSEND(X,Y)    if (!(GGMesrvr(X,Y),\
  4546.                                   GGMsockt(X,Y))) return FALSE\
  4547.  
  4548. #ifndef I370
  4549.  
  4550. #define  WRITE_FILEMODE     "w,recfm=vb,lrecl=259,blksize=6233"
  4551. #define  APPEND_FILEMODE    "a,recfm=vb,lrecl=259,blksize=6233"
  4552. #define  SYSOUT_FILEMODE    "w,recfm=vba,lrecl=133"
  4553. #define  FILEMODE             "recfm=vb,lrecl=259,blksize=6233"
  4554. #define  FILEMODE_A           "recfm=vba,lrecl=133"
  4555.  
  4556. #define  OPEN_TEXT_FILE_FOR_WRITE(F)  \
  4557.          fopen((F),WRITE_FILEMODE)
  4558.  
  4559. #define  OPEN_TEXT_FILE_FOR_APPEND(F)  \
  4560.          fopen((F),APPEND_FILEMODE)
  4561.  
  4562. #define  OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  4563.          fopen((F),(B) ? APPEND_FILEMODE : WRITE_FILEMODE)
  4564.  
  4565. #define  OPEN_OUTPUT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  4566.          fopen((F),(B) ? "a" : WRITE_FILEMODE)
  4567.  
  4568. #define  OPEN_SYSOUT_FILE(F)  \
  4569.          fopen((F),SYSOUT_FILEMODE)
  4570.  
  4571. #define  TEST_IF_FILE_EXISTS(P,F)  (P=fopen((F),"r"))
  4572. #define  CLEANUP_IF_FILE_EXISTS(P) (void)fclose(P)
  4573.  
  4574. #else
  4575.  
  4576. #define  WRITE_FILEMODE     "w,recfm=v,reclen=255,blksize=6233"
  4577. #define  APPEND_FILEMODE    "a,recfm=v,reclen=255,blksize=6233"
  4578. #define  SYSOUT_FILEMODE    "w,recfm=v,reclen=133,print=yes"
  4579. #define  FILEMODE             "recfm=v,reclen=255,blksize=6233"
  4580. #define  FILEMODE_A           "recfm=v,reclen=133,print=yes"
  4581.  
  4582. #define  OPEN_TEXT_FILE_FOR_WRITE(F)  \
  4583.          afopen((F),"w","seq",FILEMODE)
  4584.  
  4585. #define  OPEN_TEXT_FILE_FOR_APPEND(F)  \
  4586.          afopen((F),"a","seq",FILEMODE)
  4587.  
  4588. #define  OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  4589.          afopen((F),(B)?"a":"w","seq",FILEMODE)
  4590.  
  4591. #define  OPEN_OUTPUT_FILE_FOR_WRITE_OR_APPEND(F,B)  \
  4592.          afopen((F),(B)?"a":"w","seq",FILEMODE)
  4593.  
  4594. #define  OPEN_SYSOUT_FILE(F)  \
  4595.          afopen((F),"w","seq",FILEMODE_A)
  4596.  
  4597. #define  TEST_IF_FILE_EXISTS(F,P)  (access((F),0) == 0)
  4598. #define  CLEANUP_IF_FILE_EXISTS(P) /* */
  4599.  
  4600. #endif
  4601.  
  4602. #define ebdtoasc(C) {char *__cp;\
  4603.                      for(__cp = C;*__cp;__cp++) *__cp = EtoA(*__cp);}
  4604.  
  4605. #define asctoebd(C) {char *__cp;\
  4606.                      for(__cp = C;*__cp;__cp++) *__cp = AtoE(*__cp);}
  4607.  
  4608. #define uppercase_in_place(C) {char *__cp;\
  4609.                      for(__cp=C;*__cp;__cp++) *__cp = toupper(*__cp);}
  4610.  
  4611. #define lowercase_in_place(C) {char *__cp;\
  4612.                      for(__cp=C;*__cp;__cp++) *__cp = tolower(*__cp);}
  4613.  
  4614. #define copy_uppercase(A,B) {char *__cA,*__cB;\
  4615.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  4616.                          *__cA = toupper(*__cB);\
  4617.                      *__cA='\0';}
  4618.  
  4619. #define copy_lowercase(A,B) {char *__cA,*__cB;\
  4620.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  4621.                          *__cA = tolower(*__cB);\
  4622.                      *__cA='\0';}
  4623.  
  4624. #define copy_uppercase_and_strip_trailing(A,B,C) {char *__cA,*__cB;\
  4625.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  4626.                          *__cA = toupper(*__cB);\
  4627.                      for (; __cA>A && isspace(*(__cA-1)); __cA--);\
  4628.                      *__cA='\0';C=__cA;}
  4629.  
  4630. #define copy_lowercase_and_strip_trailing(A,B,C) {char *__cA,*__cB;\
  4631.                      for (__cA=A,__cB=B; *__cB;__cA++,__cB++)\
  4632.                          *__cA = tolower(*__cB);\
  4633.                      for (; __cA>A && isspace(*(__cA-1)); __cA--);\
  4634.                      *__cA='\0';C=__cA;}
  4635.  
  4636. #define skip_whitespace(C)        (C) + strspn((C)," \t")
  4637. #define skip_ISPF_whitespace(C)   (C) + strspn((C)," ,\t")
  4638. #define find_whitespace(A,B)      if (!(A=strpbrk((B)," \t")))\
  4639.                                      A = strchr((B),'\0');
  4640. #define find_ISPF_whitespace(A,B) if (!(A=strpbrk((B)," ,\t")))\
  4641.                                      A = strchr((B),'\0');
  4642.  
  4643.  
  4644. /****** Procedure and function declarations. *************************/
  4645.  
  4646. extern enum data_set_type  GGMalloc(char *, char *, enum data_set_type,
  4647.                                                                   int);
  4648. extern void                GGMbtext(struct ggcb *, struct texthdr *,
  4649.                                                                FILE *);
  4650. extern void                GGMclrtx(struct ggcb *,struct gopherinfo *);
  4651. extern Bool                GGMconn (struct ggcb *,struct connection *);
  4652. extern char               *GGMcopy (struct ggcb *, char *);
  4653. extern Bool                GGMcso  (struct ggcb *,struct gopherinfo *,
  4654.                                                                 GOHOW);
  4655. extern Bool                GGMdbm  (struct ggcb *,struct gopherinfo *);
  4656. extern void                GGMdfail(int,__S99parms *);
  4657. extern Bool                GGMdir  (struct ggcb *,struct gopherinfo *,
  4658.                                                                 GOHOW);
  4659. extern void                GGMdisc (struct ggcb *,struct connection *);
  4660. extern int                 GGMdispl(struct ggcb *, char *);
  4661. extern void                GGMdsopt(struct ggcb *, char *);
  4662. extern void                GGMdump (struct ggcb *,char *, char *, int);
  4663. extern void                GGMesrvr(struct ggcb *,struct connection *);
  4664. extern void                GGMfreem(struct ggcb *,char *,char *);
  4665. extern Bool                GGMftp  (struct recvstruct *, struct Ftp *);
  4666. extern FILE               *GGMgetds(struct ggcb *,struct extraction *);
  4667. extern void                GGMgetm (struct ggcb *,char **,int,char *);
  4668. extern Bool                GGMgofor(struct ggcb *,struct gopherinfo *,
  4669.                                                                 GOHOW);
  4670. extern Bool                GGMgsrvl(struct ggcb *,struct connection *,
  4671.                                                         char **, Fool);
  4672. extern void                GGMierr (struct ggcb *);
  4673. extern int                 GGMiget (struct ggcb *, char *);
  4674. extern void                GGMimsg (struct ggcb *, char *);
  4675. extern Bool                GGMinfo (struct ggcb *, struct gopherinfo *);
  4676. extern Bool                GGMispf (struct ggcb *, char *);
  4677. extern Bool                GGMivget(struct ggcb *, char *, char *,int);
  4678. extern Bool                GGMivput(struct ggcb *, char *, char *,int);
  4679. extern Bool                GGMmenu (struct ggcb *, char *);
  4680. extern void                GGMmtfer(int, char*);
  4681. extern struct textline    *GGMouttx(struct ggcb *, char *,
  4682.                                                   struct gopherinfo *);
  4683. extern Bool                GGMouts (struct recvstruct *, char *);
  4684. extern Bool                GGMproc (struct recvstruct *);
  4685. extern void                GGMrbfm (struct ggcb *);
  4686. extern void                GGMrperr(struct ggcb *);
  4687. extern Bool                GGMsockt(struct ggcb *,struct connection *);
  4688. extern void                GGMsopt (struct ggcb *,enum user_option);
  4689. extern char               *GGMstrlc(char *, char *);
  4690. extern Bool                GGMtnet (struct ggcb *,struct gopherinfo *,
  4691.                                                                 GOHOW);
  4692. extern int                 GGMtso  (char *);
  4693. extern char               *GGMtype (gophertype);
  4694. extern Bool                GGMunalc(char *);
  4695. extern Bool                GGMvtx  (struct ggcb *,struct gopherinfo *,
  4696.                                                                 GOHOW);
  4697. extern Bool                GGMwais (struct ggcb *,struct gopherinfo *,
  4698.                                                                 GOHOW);
  4699. extern Bool                GGMwhois(struct ggcb *,struct gopherinfo *,
  4700.                                                                 GOHOW);
  4701. extern Bool                GGMxlist(struct ggcb *,char *);
  4702. extern Bool                GGMxtx  (struct ggcb *,struct gopherinfo *,
  4703.                                                                EXTREQ);
  4704.  
  4705. #ifndef SUPPRESS_V_DECLARATION
  4706. extern void                GGMpmsg (struct ggcb *,int,char *,char *,
  4707.                                                                   ...);
  4708. #endif
  4709.  
  4710. ./ ADD NAME=GGSASC
  4711.  
  4712.  /********************************************************************/
  4713.  /*                                                                  */
  4714.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  4715.  /*                                                                  */
  4716.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  4717.  /*                                                                  */
  4718.  /* SAS modifications due to Dale Ingold at SAS Institute, Inc.      */
  4719.  /*                                                                  */
  4720.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  4721.  /* including the implied warranties of merchantability and fitness, */
  4722.  /* are expressly denied.                                            */
  4723.  /*                                                                  */
  4724.  /* Provided this copyright notice is included, this software may    */
  4725.  /* be freely distributed and not offered for sale.                  */
  4726.  /*                                                                  */
  4727.  /* Changes or modifications may be made and used only by the maker  */
  4728.  /* of same, and not further distributed.  Such modifications should */
  4729.  /* be mailed to the author for consideration for addition to the    */
  4730.  /* software and incorporation in subsequent releases.               */
  4731.  /*                                                                  */
  4732.  /********************************************************************/
  4733.  
  4734. /* ------------------- "ggsasc.h" include member ------------------- */
  4735.  
  4736. #ifdef SASC
  4737.  
  4738. #define I370
  4739.  
  4740. #include <dynam.h>
  4741.  
  4742. #define FETCH
  4743.  
  4744.  __inline void (*fetch( const char *modname ))()
  4745.  {
  4746.    void (*fpp)();
  4747.  
  4748.    loadm( modname, &fpp );
  4749.    return( fpp );
  4750.  }
  4751.  
  4752.  __inline int (*release( void (*fpp)() ))
  4753.  {
  4754.    unloadm( fpp );
  4755.    return( 0 );
  4756.  }
  4757.  
  4758.  
  4759. #ifndef __SVC99
  4760.  
  4761.   #define __SVC99  1
  4762.  
  4763.   #include <code.h>
  4764.  
  4765.   struct __S99struc
  4766.     {
  4767.       unsigned char   __S99RBLN;  /* length of request block..20      */
  4768.       unsigned char   __S99VERB;  /* verb code                        */
  4769.       unsigned short  __S99FLAG1; /* FLAGS1 field of SVC99 Req Block  */
  4770.       unsigned short  __S99ERROR; /* error code field                 */
  4771.       unsigned short  __S99INFO;  /* information reason code          */
  4772.       void           *__S99TXTPP; /* address of text unit pointer list*/
  4773.       int             __reserved; /* reserved..will always be 0       */
  4774.       unsigned int    __S99FLAG2; /* FLAGS2 field..can only be filled */
  4775.                                   /* in by APF authorized programs    */
  4776.     };
  4777.  
  4778.   typedef struct __S99struc __S99parms;
  4779.  
  4780.   __inline int svc99(__S99parms* svc99parmlist)
  4781.     { return( (_ldregs(R1, &svc99parmlist),
  4782.                _code(0, 0x9680, 0x1000),
  4783.                _code(0, 0x0a63),
  4784.                _stregs(R15) ) );
  4785.     }
  4786.  
  4787. #endif
  4788.  
  4789. #define FALSE 0
  4790. #define TRUE  1
  4791.  
  4792. #include <lcio.h>
  4793.  
  4794. #define  MAXHOSTNAMELEN     64
  4795.  
  4796. #define  __ctest(X)  fprintf(stderr,\
  4797.                      "GGMVS: CTEST is not supported by this compiler.")
  4798.  
  4799. #endif
  4800.  
  4801. ./ ADD NAME=GGUSER
  4802.  
  4803.  /********************************************************************/
  4804.  /*                                                                  */
  4805.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  4806.  /*                                                                  */
  4807.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  4808.  /*                                                                  */
  4809.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  4810.  /* including the implied warranties of merchantability and fitness, */
  4811.  /* are expressly denied.                                            */
  4812.  /*                                                                  */
  4813.  /* Provided this copyright notice is included, this software may    */
  4814.  /* be freely distributed and not offered for sale.                  */
  4815.  /*                                                                  */
  4816.  /* Changes or modifications may be made and used only by the maker  */
  4817.  /* of same, and not further distributed.  Such modifications should */
  4818.  /* be mailed to the author for consideration for addition to the    */
  4819.  /* software and incorporation in subsequent releases.               */
  4820.  /*                                                                  */
  4821.  /********************************************************************/
  4822.  
  4823. /* ------------------- "gguser.h" include member ------------------- */
  4824.  
  4825. /* Include file for locally customized values. */
  4826.  
  4827. /* Define levels of C/370 and TCP/IP.  This controls support for
  4828.  * fetching of non-C load modules and socket error reporting.
  4829.  */
  4830.  
  4831. /* #define  C370V1    /* define this if C/370 Version 1 */
  4832.    #define  C370V2    /* define this if C/370 Version 2 or higher */
  4833. /* #define  SASC      /* define this if SAS/C compiler */
  4834.  
  4835. /* #define  TCPIPV1   /* define this if TCP/IP Version 1 */
  4836.    #define  TCPIPV2   /* define this if TCP/IP Version 2 or higher */
  4837. /* #define  SNSTCPIP  /* define this if SNS/TCPAccess    */
  4838.  
  4839. /* #define  ISPFV2    /* define this if ISPF Version 2 or earlier */
  4840.    #define  ISPFV3    /* define this if ISPF Version 3 or later   */
  4841.  
  4842. /*
  4843.  * Define this if you want DEST, FORMS and UCB for print requests.
  4844.  * Undefine it if you don't (you get just CLASS and COPIES).
  4845.  */
  4846.  
  4847.    #define FULLSYSOUT
  4848. /* #undef  FULLSYSOUT */
  4849.  
  4850. /* Define the following defaults for your installation. */
  4851. /* Use XTELNET if you like the CSOCK package from UCLA. */
  4852.  
  4853.    #define  TELNET_COMMAND_NAME     "TELNET"
  4854. /* #define  TELNET_COMMAND_NAME     "XTELNET" */
  4855.  
  4856. /* Define the following if you want to use the autologin */
  4857. /* feature of XTELNET (i.e. XTELNET -l userid(/password) */
  4858.  
  4859. /* #define  XTELNET_AUTOLOGIN */
  4860.    #undef   XTELNET_AUTOLOGIN
  4861.  
  4862. /* Define this if the server host name set by the "+" frob
  4863.  * should have the domain name appended.  Note that this will
  4864.  * affect how the hostname needs to be specified for a
  4865.  * Path=(pdsmember) specification - it must match the local host
  4866.  * the way it is generated here.  Of course, host=+ will do it anyway.
  4867.  */
  4868.  
  4869.    #define  APPEND_DOMAIN_NAME_TO_SELF
  4870. /* #undef   APPEND_DOMAIN_NAME_TO_SELF */
  4871.  
  4872. /*
  4873.  * Turn on for TCP-level debugging output (you probably don't want to
  4874.  * unless your TCP/IP stuff is really broken and I can't help you).
  4875.  */
  4876.  
  4877. /* #define DEBUG       */
  4878.    #undef  DEBUG
  4879.  
  4880. /*
  4881.  * Turn on for MTF-level debugging output.
  4882.  */
  4883.  
  4884. /* #define DEBUGMTF    */
  4885.    #undef  DEBUGMTF
  4886.  
  4887. /* Server and MTF stuff. */
  4888.  
  4889. /* #define  MTF_TASKS           8 */
  4890. #define  MTF_TASKS           1  /* lest REXX multitasking lossage */
  4891. #define  TCP_QUEUE_LENGTH   20
  4892. #define  SERV_TCP_PORT      70
  4893. #define  CONNECT_TIME_OUT   60
  4894. #define  DEFAULT_DIRECTORY  "DD:GGGOPHER"
  4895. #define  ACCESS_TABLE       "DD:GGACCESS"
  4896. #define  DEBUG_FILE         "DD:GGDEBUG"
  4897. #define  PARAMETER_FILE     "DD:GGPARMS"
  4898. #define  MY_DOMAIN_SUFFIX   ".DRAPER.COM"
  4899.  
  4900. /* note: could get MY_DOMAIN_SUFFIX from TCPIP startup - what call? */
  4901.  
  4902. /* Client stuff. */
  4903.  
  4904. #define  INITIAL_TYPE   GOPHER_DIRECTORY
  4905. #define  INITIAL_PORT   GOPHER_PORT_NUMBER
  4906. #define  INITIAL_PATH   ""
  4907. #define  INITIAL_HOST   "MVS.DRAPER.COM"
  4908. #define  INITIAL_DESC   "Root"
  4909.  
  4910. /* Server and client stuff. */
  4911.  
  4912. #define  IDENT_HOST_FROB    "+"
  4913. #define  LOCAL_HOST_FROB    "-"
  4914.  
  4915. /********************************************************************/
  4916. /*  following are "gopher" record types.   */
  4917. /********************************************************************/
  4918.  
  4919. #define  GFILE    '0'
  4920. #define  MENU     '1'
  4921. #define  ERROR    '2'
  4922. #define  INDEX    '7'
  4923. #define  TELNET   '8'
  4924. #define  TN3270   'T'
  4925. #define  WHOIS    'w'
  4926.  
  4927. /********************************************************************/
  4928. /* following are MVS file type identifiers.  They must appear at the
  4929.    beginning of the file they're identifying.                        */
  4930. /********************************************************************/
  4931.  
  4932. #define  MENUIDENT    "GOPHER_MENU"
  4933. #define  INDEXIDENT   "GOPHER_INDEX"
  4934.  
  4935. /********************************************************************/
  4936. /*  following are tokens for menu GOPHER identifiers.    */
  4937. /********************************************************************/
  4938.  
  4939. #define  TOKTYPE      "TYPE"
  4940. #define  TYPETOK      0
  4941. #define  TOKNAME      "NAME"
  4942. #define  NAMETOK      1
  4943. #define  TOKPATH      "PATH"
  4944. #define  PATHTOK      2
  4945. #define  TOKHOST      "HOST"
  4946. #define  HOSTTOK      3
  4947. #define  TOKPORT      "PORT"
  4948. #define  PORTTOK      4
  4949. #define  TOKEND       "END"
  4950. #define  ENDTOK       5
  4951. #define  TOKCOMMENT   "*"
  4952. #define  COMMENTTOK   6
  4953.  
  4954. #define  TOKDISPLAY   "DISPLAY"
  4955. #define  DISPLAYTOK   7
  4956. #define  TOKSELECT    "SELECTOR"
  4957. #define  SELECTTOK    8
  4958.  
  4959. /********************************************************************/
  4960. /*  types of   "types" - operands of the TYPE keyword in directories.*/
  4961. /********************************************************************/
  4962.  
  4963. #define  TYPEFILE    "FILE"
  4964. #define  TYPEMENU    "DIRECTORY"
  4965. #define  TYPEINDEX   "INDEX"
  4966. #define  TYPETELNET  "TELNET"
  4967. #define  TYPETN3270  "TN3270"
  4968. #define  TYPEWHOIS   "WHOIS"
  4969.  
  4970. /********************************************************************/
  4971. /*  used by the REXX Interface                                      */
  4972. /********************************************************************/
  4973.  
  4974.   /* Be sure to include all 8 bytes, including blanks, in below */
  4975.  
  4976. #define  REXX_EXEC_LIBRARY_DDNAME   "GGEXEC  "
  4977. #define  REXX_EXEC_SUBCOM           "        "
  4978.  
  4979. ./ ENDUP
  4980. ?!
  4981. //C        EXEC MDLOAD,BS='6160',TRK1='25',TRK2='1',TO='C'
  4982. //SYSIN    DD   DATA,DLM='?!'
  4983. ./ ADD NAME=GGCLIENT
  4984.  
  4985.  /********************************************************************/
  4986.  /*                                                                  */
  4987.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  4988.  /*                                                                  */
  4989.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  4990.  /*                                                                  */
  4991.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  4992.  /* including the implied warranties of merchantability and fitness, */
  4993.  /* are expressly denied.                                            */
  4994.  /*                                                                  */
  4995.  /* Provided this copyright notice is included, this software may    */
  4996.  /* be freely distributed and not offered for sale.                  */
  4997.  /*                                                                  */
  4998.  /* Changes or modifications may be made and used only by the maker  */
  4999.  /* of same, and not further distributed.  Such modifications should */
  5000.  /* be mailed to the author for consideration for addition to the    */
  5001.  /* software and incorporation in subsequent releases.               */
  5002.  /*                                                                  */
  5003.  /********************************************************************/
  5004.  
  5005. #ifdef SASC
  5006. #pragma  runopts(EXECOPS)
  5007. #else
  5008. #pragma  runopts(heap(8k,8k,anywhere,))
  5009. #pragma  runopts(nospie,nostae)
  5010. #endif
  5011.  
  5012. #pragma  csect(code,  "GG@LIENT")
  5013. #pragma  csect(static,"GG$LIENT")
  5014. #include "gg.h"
  5015.  
  5016. /*********************************************************************/
  5017.  
  5018. static char copyright_notice[] =
  5019.    "Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992   \n\
  5020.                                                                     \n\
  5021.     GOPHER server due to Shawn Hart at the University of Delaware.  \n\
  5022.                                                                     \n\
  5023.     This software is provided on an 'AS IS' basis.  All warranties, \n\
  5024.     including the implied warranties of merchantability and fitness,\n\
  5025.     are expressly denied.                                           \n\
  5026.                                                                     \n\
  5027.     Provided this copyright notice is included, this software may   \n\
  5028.     be freely distributed and not offered for sale.                 \n\
  5029.                                                                     \n\
  5030.     Changes or modifications may be made and used only by the maker \n\
  5031.     of same, and not further distributed.  Such modifications should\n\
  5032.     be mailed to the author for consideration for addition to the   \n\
  5033.     software and incorporation in subsequent releases.";
  5034.  
  5035. /*********************************************************************/
  5036.  
  5037. #ifdef I370
  5038. char * _style = "tso:";
  5039. #endif
  5040.  
  5041. /*********************************************************************/
  5042.  
  5043. static void
  5044. trap_ispf_command(gp,verb,action)
  5045. Rstruc ggcb      *gp;
  5046. char             *verb;
  5047. char             *action;
  5048. {
  5049.  char             zcttrunc [16];
  5050.  char             zctact   [64];
  5051.  char             zctdesc [128];
  5052.  
  5053.  if (!GGMivput(gp,"ZCTVERB ",verb,-1)) return;
  5054.  
  5055.  if (!GGMispf(gp,"TBTOP ISPCMDS")) return;
  5056.  if (!GGMispf(gp,"TBSCAN ISPCMDS ARGLIST(ZCTVERB)")) return;
  5057.  if (!GGMivget(gp,"ZCTACT ",zctact,sizeof(zctact)))  return;
  5058.  if (UNEQUAL(zctact,action)) {
  5059.    GGMivget(gp,"ZCTTRUNC ",zcttrunc, sizeof(zcttrunc));
  5060.    GGMivget(gp,"ZCTDESC  ",zctdesc,sizeof(zctdesc));
  5061.    if (!GGMispf(gp,"TBTOP ISPCMDS ")) return;
  5062.    GGMivput(gp,"ZCTACT   ",action   ,-1);
  5063.    GGMivput(gp,"ZCTTRUNC ",zcttrunc ,-1);
  5064.    GGMivput(gp,"ZCTDESC  ",zctdesc  ,-1);
  5065.    if (!GGMispf(gp,"TBADD ISPCMDS ")) return;
  5066.  }
  5067.  
  5068.  return;
  5069. }
  5070.  
  5071. /*********************************************************************/
  5072.  
  5073. static Bool
  5074. go_for_it(gp,ip)
  5075. struct ggcb            *gp;
  5076. struct gopherinfo      *ip;
  5077. {
  5078.  char                   temp   [32];
  5079.  
  5080.  (void)GGMivget(gp,"GGHOST ",ip->host,sizeof(ip->host));
  5081.  (void)GGMivget(gp,"GGPATH ",ip->path,sizeof(ip->path));
  5082.  (void)GGMivget(gp,"GGDESC ",ip->desc,sizeof(ip->desc));
  5083.  (void)GGMivget(gp,"GGPORT ",temp    ,sizeof(temp)    );
  5084.  ip->type = INITIAL_TYPE;
  5085.  if (!*ip->path) strcpy(ip->path,INITIAL_PATH);
  5086.  if (!*ip->host) strcpy(ip->host,INITIAL_HOST);
  5087.  if (!*ip->desc) strcpy(ip->desc,INITIAL_DESC);
  5088.  ip->port = atoi(temp);
  5089.  if (ip->port == 0) ip->port = INITIAL_PORT;
  5090.  *ip->bmds = '\0';
  5091.  
  5092.  return GGMgofor(gp,ip,AS_NORMAL);
  5093.  
  5094. }
  5095.  
  5096. /*********************************************************************/
  5097.  
  5098. int
  5099. main(argc,argv)
  5100. int      argc;
  5101. char   **argv;
  5102.  
  5103. {
  5104.  struct ggcb            *gp;
  5105.  struct gopherinfo      *ip;
  5106.  struct connection      *sp;
  5107.  char                   *p;
  5108.  int                     i;
  5109.  int                     exit_return_code;
  5110.  Bool                    bypass_startup;
  5111.  struct ggcb             gg;
  5112.  char                    ggdomain [129];
  5113.  char                    ggtelnet [129];
  5114.  char                    zerrsm [25];
  5115.  char                    zerrlm [ZERRLM_SIZE];
  5116.  
  5117.  exit_return_code = 0;
  5118.  
  5119.  memset(&gg,0,sizeof(struct ggcb));
  5120.  
  5121.  gp = ≫
  5122.  
  5123.  /* set up top-level gopherinfo structure */
  5124.  
  5125.  GETMAIN(ip, struct gopherinfo, 1, "top-level gopherinfo struct");
  5126.  if (!ip) {
  5127.    fprintf(stderr,"Not enough memory to start up GOPHER\n");
  5128.    exit(16);
  5129.  }
  5130.  
  5131.  memset(ip,0,sizeof(struct gopherinfo));
  5132.  
  5133.  gp->ginfo = ip;
  5134.  
  5135.  gp->test_mode  = FALSE;
  5136.  gp->debug_mode = FALSE;
  5137.  gp->local_mode = FALSE;
  5138.  bypass_startup = FALSE;
  5139.  
  5140.  for (i = 1; i < argc; i++) {
  5141.    p = argv[i];
  5142.    if (*p == '-') {
  5143.      while (*++p) {
  5144.        switch (toupper(*p)) {
  5145.          case 'T':  gp->test_mode  = TRUE;    break;
  5146.          case 'D':  gp->debug_mode = TRUE;    break;
  5147.          case 'L':  gp->local_mode = TRUE;    break;
  5148.          case 'Q':  bypass_startup = TRUE;    break;
  5149.          default: fprintf(stderr,"GGMVS: Bad parameter flag %c\n", *p);
  5150.                   exit_return_code = 8;
  5151.        }
  5152.      }
  5153.    }
  5154.    else {
  5155.      fprintf(stderr,"GGMVS: Bad parameter string %s\n",p);
  5156.      exit_return_code = 8;
  5157.    }
  5158.  }
  5159.  
  5160.  if (gp->test_mode) __ctest(NULL);
  5161.  
  5162.  if (gp->debug_mode) {
  5163.    if (!(gp->debug_file = fopen(DEBUG_FILE,"w"))) {
  5164.      perror(DEBUG_FILE);
  5165.      exit_return_code = 4;
  5166.    }
  5167.  }
  5168.  else gp->debug_file = NULL;
  5169.  
  5170.  gp->thdr.first_text_line = NULL;
  5171.  
  5172.  GGMclrtx(gp,NULL);               /* Clear text       */
  5173.  GGMclrtx(gp,ip);                 /* Clear text       */
  5174.  
  5175.  sp = &gp->gopher_connection;
  5176.  
  5177.  /* These will be able to be set from gopherrc. */
  5178.  
  5179.  gp->myport   = SERV_TCP_PORT;
  5180.  gp->mytelnet = TELNET_COMMAND_NAME;
  5181.  gp->mydomain = MY_DOMAIN_SUFFIX;
  5182.  
  5183.  /* Determine the local path name. Done in GGMCONN when needed now */
  5184.  
  5185.  strcpy(gp->ggserver,"");
  5186.  sp->connected_to_server   = FALSE;
  5187.  
  5188.  GETMAIN(sp->server_buf,    char,SERVER_BUF_MSGSIZE+4,"server buffer");
  5189.  GETMAIN(sp->client_buf,    char,CLIENT_BUF_MSGSIZE+4,"client buffer");
  5190.  GETMAIN(gp->gopher_command,char,CLIENT_BUF_MSGSIZE+4,"gopher command");
  5191.  
  5192. #ifdef FETCH
  5193.  
  5194.  gp->isplink_pointer = (int (*) ())fetch("ISPLINK");
  5195.  gp->ispexec_pointer = (int (*) ())fetch("ISPEXEC");
  5196.  
  5197. #endif
  5198.  
  5199.  if (!GGMispf(gp,"CONTROL ERRORS RETURN")) exit_return_code = 20;
  5200.  
  5201.  else {
  5202.  
  5203.    exit_return_code = 0;
  5204.  
  5205.    trap_ispf_command(gp,"RFIND","&YRFIND");  /* enable RFIND */
  5206.  
  5207.    (void)GGMispf(gp,"VGET (GGDOMAIN GGTELNET) PROFILE");
  5208.    (void)GGMivget(gp,"GGDOMAIN ",ggdomain, sizeof(ggdomain));
  5209.    (void)GGMivget(gp,"GGTELNET ",ggtelnet, sizeof(ggtelnet));
  5210.    if (*ggdomain) gp->mydomain = ggdomain;
  5211.    if (*ggtelnet) gp->mytelnet = ggtelnet;
  5212.  
  5213.    GGMsopt(gp,OPTION_ALL);      /* set options */
  5214.  
  5215.  
  5216.    if (bypass_startup) {
  5217.      (void)GGMispf(gp,"VGET (GGHOST GGPATH GGDESC GGPORT) PROFILE");
  5218.      (void)go_for_it(gp,ip);
  5219.    }
  5220.    else {
  5221.      (void)GGMivput(gp,"ZCMD "    ,"",-1);
  5222.      while (GGMdispl(gp,"GGM     ") == 0
  5223.          && !gp->quit
  5224.          && !go_for_it(gp,ip)) ;
  5225.    }
  5226.  }
  5227.  
  5228.  if (gp->setmsg) {
  5229.    (void)GGMivget(gp,"ZERRSM ",zerrsm, sizeof(zerrsm));
  5230.    (void)GGMivget(gp,"ZERRLM ",zerrlm, sizeof(zerrlm));
  5231.    fprintf(stderr,"%s: %s\n",zerrsm,zerrlm);
  5232.    gp->setmsg = FALSE;
  5233.  }
  5234.  
  5235.  if (sp->connected_to_server) {
  5236.    GGMdisc(gp,sp);            /* disconnect from gopher server */
  5237.  }
  5238.  
  5239.  FREEMAIN(gp->gopher_command,"gopher command");
  5240.  FREEMAIN(sp->server_buf,    "server buffer");
  5241.  FREEMAIN(sp->client_buf,    "client buffer");
  5242.  FREEMAIN(ip,                "top-level gopherinfo struct");
  5243.  
  5244.  #define FINAL_CLOSE(A,B) \
  5245.    if (A) { \
  5246.             if (fclose(A) < 0) fprintf(stderr,B); \
  5247.           }
  5248.  
  5249.  FINAL_CLOSE(gp->debug_file, "Error closing debug file\n");
  5250.  
  5251.  exit(exit_return_code);
  5252. }
  5253.  
  5254. ./ ADD NAME=GGMALLOC
  5255.  
  5256.  /********************************************************************/
  5257.  /*                                                                  */
  5258.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  5259.  /*                                                                  */
  5260.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  5261.  /*                                                                  */
  5262.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  5263.  /* including the implied warranties of merchantability and fitness, */
  5264.  /* are expressly denied.                                            */
  5265.  /*                                                                  */
  5266.  /* Provided this copyright notice is included, this software may    */
  5267.  /* be freely distributed and not offered for sale.                  */
  5268.  /*                                                                  */
  5269.  /* Changes or modifications may be made and used only by the maker  */
  5270.  /* of same, and not further distributed.  Such modifications should */
  5271.  /* be mailed to the author for consideration for addition to the    */
  5272.  /* software and incorporation in subsequent releases.               */
  5273.  /*                                                                  */
  5274.  /********************************************************************/
  5275.  
  5276. #pragma  csect(code,  "GG@ALLOC")
  5277. #pragma  csect(static,"GG$ALLOC")
  5278. #include "gg.h"
  5279.  
  5280. /****** Allocate a data set. *****************************************/
  5281.  
  5282. enum data_set_type
  5283. GGMalloc(dsname,ddname,wanted_type,nitems)
  5284. char                      *dsname;
  5285. char                      *ddname;
  5286. enum data_set_type         wanted_type;
  5287. int                        nitems;
  5288. {
  5289.  int                       i;
  5290.  int                       rc;
  5291.  char                     *cp;
  5292.  enum data_set_type        return_type;
  5293.  Bool                      try_new;
  5294.  short                     primary_allocation   ;
  5295.  short                     secondary_allocation ;
  5296.  short                     directory_blocks     ;
  5297.  short                     dsorg                ;
  5298.  __S99parms                stuff99; /* No "struct", despite manual */
  5299.  TEXTUNIT                 *tu [17];
  5300.  TEXTUNIT                  tu_dsn;
  5301.  TEXTUNIT                  tu_ddn;
  5302.  TEXTUNIT                  tu_member;
  5303.  TEXTUNIT                  tu_stat;
  5304.  TEXTUNIT                  tu_disp;
  5305.  TEXTUNIT                  tu_perm;
  5306.  TEXTUNIT                  tu_rtddn;
  5307.  TEXTUNIT                  tu_rtorg;
  5308.  TEXTUNIT                  tu_block;
  5309.  TEXTUNIT                  tu_prime;
  5310.  TEXTUNIT                  tu_sec;
  5311.  TEXTUNIT                  tu_dir;
  5312.  TEXTUNIT                  tu_recfm;
  5313.  TEXTUNIT                  tu_lrecl;
  5314.  TEXTUNIT                  tu_blksz;
  5315.  TEXTUNIT                  tu_dsorg;
  5316.  char                     *lparp;
  5317.  char                     *rparp;
  5318.  char                      dsnseq [81];
  5319.  char                      member [81];
  5320.  char                      what_to_open[81];
  5321.  FILE                     *mfile;
  5322.  
  5323.  try_new = FALSE;
  5324.  
  5325.  memset((char *)&stuff99,0,sizeof(__S99parms));
  5326.  
  5327.  strcpy(member,"");
  5328.  strcpy(dsnseq,dsname);
  5329.  lparp = strchr(dsnseq,'(');
  5330.  rparp = strchr(dsnseq,')');
  5331.  if (lparp && rparp && (lparp < rparp) && (*(rparp+1) == '\0')) {
  5332.    *lparp = '\0';            /* makes dsnseq the seq part only */
  5333.    *rparp = '\0';            /* turns member into a string     */
  5334.    strcpy(member, lparp+1);
  5335.    wanted_type = PDS;
  5336.  }
  5337.  
  5338.  for (;;) {
  5339.  
  5340.    stuff99.__S99RBLN   = 20;
  5341.    stuff99.__S99VERB   = S99VRBAL;
  5342.    stuff99.__S99FLAG1  = S99NOCNV << 8;
  5343.    stuff99.__S99ERROR  = 0;
  5344.    stuff99.__S99INFO   = 0;
  5345.    stuff99.__S99TXTPP  = tu;
  5346.    stuff99.__S99FLAG2  = 0;
  5347.  
  5348.    i = 0;
  5349.  
  5350.    tu[i++] = &tu_dsn;
  5351.  
  5352.    tu_dsn.key        = DALDSNAM;
  5353.    tu_dsn.num        = 1;
  5354.    tu_dsn.ent.len    = strlen(dsnseq);
  5355.    strcpy(tu_dsn.ent.prm,dsnseq);
  5356.    for (cp=tu_dsn.ent.prm; *cp; cp++) *cp = toupper(*cp);
  5357.  
  5358.    tu[i++] = &tu_stat;
  5359.  
  5360.    tu_stat.key      = DALSTATS;
  5361.    tu_stat.num      = 1;
  5362.    tu_stat.ent.len  = 1;
  5363.    *tu_stat.ent.prm = (try_new ? NEW : SHR);
  5364.  
  5365.    tu[i++] = &tu_disp;
  5366.  
  5367.    tu_disp.key      = DALNDISP;
  5368.    tu_disp.num      = 1;
  5369.    tu_disp.ent.len  = 1;
  5370.    *tu_disp.ent.prm = (try_new ? CATLG : KEEP);
  5371.  
  5372.    tu[i++] = &tu_rtorg;
  5373.  
  5374.    tu_rtorg.key     = DALRTORG;
  5375.    tu_rtorg.num     = 1;
  5376.    tu_rtorg.ent.len = 2;
  5377.  
  5378.    if (*member) {
  5379.  
  5380.      tu[i++] = &tu_member;
  5381.  
  5382.      tu_member.key     = DALMEMBR;
  5383.      tu_member.num     = 1;
  5384.      tu_member.ent.len = strlen(member);
  5385.      strcpy(tu_member.ent.prm,member);
  5386.      for (cp=tu_member.ent.prm; *cp; cp++) *cp = toupper(*cp);
  5387.  
  5388.    }
  5389.  
  5390.    if (ddname && *ddname) {
  5391.  
  5392.      tu[i++] = &tu_ddn;
  5393.  
  5394.      tu_ddn.key     = DALDDNAM;
  5395.      tu_ddn.num     = 1;
  5396.      tu_ddn.ent.len = strlen(ddname);
  5397.      strcpy(tu_ddn.ent.prm,ddname);
  5398.      for (cp=tu_ddn.ent.prm; *cp; cp++) *cp = toupper(*cp);
  5399.  
  5400.      tu[i++] = &tu_perm;
  5401.  
  5402.      tu_perm.key     = DALPERMA;
  5403.      tu_perm.num     = 0;
  5404.    }
  5405.    else {
  5406.  
  5407.      tu[i++] = &tu_rtddn;
  5408.  
  5409.      tu_rtddn.key     = DALRTDDN;
  5410.      tu_rtddn.num     = 1;
  5411.      tu_rtddn.ent.len = 8;
  5412.      memset(tu_rtddn.ent.prm,' ',8);
  5413.  
  5414.    }
  5415.  
  5416.    if (try_new) {
  5417.  
  5418.      switch (wanted_type) {
  5419.        case PDS:
  5420.                  primary_allocation   = (short)nitems;
  5421.                  secondary_allocation = primary_allocation;
  5422.                  directory_blocks     = ((short)nitems/(12*36)+1) * 36;
  5423.                  dsorg                = DSORG_PO;
  5424.                  break;
  5425.        case SEQ:
  5426.        default:
  5427.                  primary_allocation   = (short)nitems;
  5428.                  secondary_allocation = primary_allocation;
  5429.                  directory_blocks     = 0;
  5430.                  dsorg                = DSORG_PS;
  5431.                  break;
  5432.      }
  5433.  
  5434.      tu[i++] = &tu_block;
  5435.  
  5436.      tu_block.key     = DALBLKLN;
  5437.      tu_block.num     = 1;
  5438.      tu_block.ent.len = 3;
  5439.      memset(tu_block.ent.prm,0,3);
  5440.      *(short *)(tu_block.ent.prm+1) = 6233;
  5441.  
  5442.      tu[i++] = &tu_prime;
  5443.  
  5444.      tu_prime.key     = DALPRIME;
  5445.      tu_prime.num     = 1;
  5446.      tu_prime.ent.len = 3;
  5447.      memset(tu_prime.ent.prm,0,3);
  5448.      *(short *)(tu_prime.ent.prm+1) = primary_allocation;
  5449.  
  5450.      tu[i++] = &tu_sec;
  5451.  
  5452.      tu_sec.key     = DALSECND;
  5453.      tu_sec.num     = 1;
  5454.      tu_sec.ent.len = 3;
  5455.      memset(tu_sec.ent.prm,0,3);
  5456.      *(short *)(tu_sec.ent.prm+1) = secondary_allocation;
  5457.  
  5458.      tu[i++] = &tu_dir;
  5459.  
  5460.      tu_dir.key     = DALDIR;
  5461.      tu_dir.num     = 1;
  5462.      tu_dir.ent.len = 3;
  5463.      memset(tu_dir.ent.prm,0,3);
  5464.      *(short *)(tu_dir.ent.prm+1) = directory_blocks;
  5465.  
  5466.      tu[i++] = &tu_recfm;
  5467.  
  5468.      tu_recfm.key        = DALRECFM;
  5469.      tu_recfm.num        = 1;
  5470.      tu_recfm.ent.len    = 1;
  5471.      *tu_recfm.ent.prm   = RECFM_VB;
  5472.  
  5473.      tu[i++] = &tu_lrecl;
  5474.  
  5475.      tu_lrecl.key        = DALLRECL;
  5476.      tu_lrecl.num        = 1;
  5477.      tu_lrecl.ent.len    = 2;
  5478.      *(short *)tu_lrecl.ent.prm   = 259;
  5479.  
  5480.      tu[i++] = &tu_blksz;
  5481.  
  5482.      tu_blksz.key        = DALBLKSZ;
  5483.      tu_blksz.num        = 1;
  5484.      tu_blksz.ent.len    = 2;
  5485.      *(short *)tu_blksz.ent.prm   = 6233;
  5486.  
  5487.      tu[i++] = &tu_dsorg;
  5488.  
  5489.      tu_dsorg.key        = DALDSORG;
  5490.      tu_dsorg.num        = 1;
  5491.      tu_dsorg.ent.len    = 2;
  5492.      *(short *)tu_dsorg.ent.prm   = dsorg;
  5493.  
  5494.    }
  5495.  
  5496.    tu[i] = (void *)0x80000000;
  5497.  
  5498.    rc = svc99(&stuff99);
  5499.  
  5500.    if (rc == 0) {
  5501.      if (!(ddname && *ddname)) {
  5502.        memcpy(ddname,(char *)tu_rtddn.ent.prm,8);
  5503.        *(ddname+8) = ' ';
  5504.        *(strchr(ddname,' ')) = '\0';
  5505.      }
  5506.      switch (tu_rtorg.ent.prm[0]) {
  5507.        case 0x40:  return_type = SEQ; break;
  5508.        case 0x02:  return_type = PDS; break;
  5509.        default:    return_type = UNK; break;
  5510.      }
  5511.      if (wanted_type == SEQ && return_type != SEQ) {
  5512.        fprintf(stderr,"%s: not a sequential data set\n",dsname);
  5513.      }
  5514.      if (wanted_type == PDS && return_type != PDS) {
  5515.        fprintf(stderr,"%s: not a partitioned data set\n",dsname);
  5516.      }
  5517.      if (return_type == PDS && *member) return SEQ;
  5518.      else return return_type;
  5519.    }
  5520.    else if (!try_new && nitems != 0 && stuff99.__S99ERROR == 0x1708) {
  5521.     try_new = TRUE;
  5522.     continue;
  5523.    }
  5524.    else {
  5525.      GGMdfail(rc,&stuff99);
  5526.      return UNK;
  5527.    }
  5528.  }
  5529. }
  5530.  
  5531. ./ ADD NAME=GGMCLRTX
  5532.  
  5533.  /********************************************************************/
  5534.  /*                                                                  */
  5535.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  5536.  /*                                                                  */
  5537.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  5538.  /*                                                                  */
  5539.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  5540.  /* including the implied warranties of merchantability and fitness, */
  5541.  /* are expressly denied.                                            */
  5542.  /*                                                                  */
  5543.  /* Provided this copyright notice is included, this software may    */
  5544.  /* be freely distributed and not offered for sale.                  */
  5545.  /*                                                                  */
  5546.  /* Changes or modifications may be made and used only by the maker  */
  5547.  /* of same, and not further distributed.  Such modifications should */
  5548.  /* be mailed to the author for consideration for addition to the    */
  5549.  /* software and incorporation in subsequent releases.               */
  5550.  /*                                                                  */
  5551.  /********************************************************************/
  5552.  
  5553. #pragma  csect(code,  "GG@CLRTX")
  5554. #pragma  csect(static,"GG$CLRTX")
  5555. #include "gg.h"
  5556.  
  5557. /****** Clear text. **************************************************/
  5558.  
  5559. void
  5560. GGMclrtx(gp,ip)
  5561. Rstruc ggcb           *gp;
  5562. Rstruc gopherinfo     *ip;
  5563.  
  5564. {
  5565.  Rstruc texthdr       *thp;
  5566.  Rstruc textline      *tp1;
  5567.  Rstruc textline      *tp2;
  5568.  
  5569.  /* If info is not specified, use main ggcb, else info's text */
  5570.  
  5571.  thp = (ip ? &ip->thdr : &gp->thdr);
  5572.  
  5573.  tp1=thp->first_text_line;
  5574.  while (tp1) {
  5575.   tp2 = tp1->next;
  5576.   FREEMAIN(tp1,"text line");
  5577.   tp1 = tp2;
  5578.  }
  5579.  
  5580.  thp->text_body_line    = NULL;
  5581.  thp->first_text_line   = NULL;
  5582.  thp->current_text_line = NULL;
  5583.  thp->last_text_line    = NULL;
  5584.  thp->text_line_count   = 0;
  5585.  thp->text_max_length   = 0;
  5586.  thp->text_max_tab_expanded_length   = 0;
  5587.  
  5588.  return;
  5589.  
  5590. }
  5591.  
  5592. ./ ADD NAME=GGMCONN
  5593.  
  5594.  /********************************************************************/
  5595.  /*                                                                  */
  5596.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  5597.  /*                                                                  */
  5598.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  5599.  /*                                                                  */
  5600.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  5601.  /* including the implied warranties of merchantability and fitness, */
  5602.  /* are expressly denied.                                            */
  5603.  /*                                                                  */
  5604.  /* Provided this copyright notice is included, this software may    */
  5605.  /* be freely distributed and not offered for sale.                  */
  5606.  /*                                                                  */
  5607.  /* Changes or modifications may be made and used only by the maker  */
  5608.  /* of same, and not further distributed.  Such modifications should */
  5609.  /* be mailed to the author for consideration for addition to the    */
  5610.  /* software and incorporation in subsequent releases.               */
  5611.  /*                                                                  */
  5612.  /********************************************************************/
  5613.  
  5614. #pragma  csect(code,  "GG@CONN ")
  5615. #pragma  csect(static,"GG$CONN ")
  5616. #include "gg.h"
  5617.  
  5618. /****** Internet address formatter. **********************************/
  5619.  
  5620. static void
  5621. format_ip_address(ia,is)
  5622. IPADDRESS   ia;
  5623. char       *is;
  5624. {
  5625.  char *cp = (char *)&ia;
  5626.  
  5627.  sprintf(is,"%d.%d.%d.%d",*cp,*(cp+1),*(cp+2),*(cp+3));
  5628.  return;
  5629. }
  5630.  
  5631. /****** Get client hostname and IP address. **************************/
  5632.  
  5633. static Bool
  5634. get_client_hostname(gp)
  5635. Rstruc ggcb        *gp;
  5636. {
  5637.  struct hostent    *client_hp;
  5638.  int                gethostnamerc;
  5639.  int                hostlen;
  5640.  int                domslen;
  5641.  
  5642.  gethostnamerc = gethostname(gp->client_hostname,MAXHOSTNAMELEN);
  5643.  if (gethostnamerc < 0) {
  5644.    fprintf(stderr,"GGMVS: gethostname() failed, don't know my name\n");
  5645.    return FALSE;
  5646.  }
  5647.  
  5648. #ifdef APPEND_DOMAIN_NAME_TO_SELF
  5649.  
  5650.  hostlen = strlen(gp->client_hostname);
  5651.  domslen = strlen(gp->mydomain);
  5652.  if (hostlen <= domslen ||
  5653.     memcmp(gp->client_hostname+hostlen-domslen,gp->mydomain,domslen)) {
  5654.    strncat(gp->client_hostname,gp->mydomain,domslen);
  5655.  }
  5656.  
  5657. #endif
  5658.  
  5659.  uppercase_in_place(gp->client_hostname);
  5660.  
  5661.  client_hp = gethostbyname(gp->client_hostname);
  5662.  if (!client_hp) {
  5663.    fprintf(stderr,
  5664.            "GGMCONN: gethostbyname(%s) failed, can't get my name\n",
  5665.            gp->client_hostname);
  5666.    return FALSE;
  5667.  }
  5668.  
  5669.  strcpy(gp->ggclient,gp->client_hostname);
  5670.  strcpy(gp->client_hostname, client_hp->h_name);
  5671.  gp->client_ip_address = *(IPADDRESS *)client_hp->h_addr;
  5672.  
  5673.  return TRUE ;
  5674.  
  5675. }
  5676.  
  5677. /****** Connect to news server. **************************************/
  5678.  
  5679. Bool
  5680. GGMconn(gp,sp)
  5681. Rstruc ggcb        *gp;
  5682. Rstruc connection  *sp;
  5683. {
  5684.  char              *lp;
  5685.  char              *cp;
  5686.  struct recvstruct *R;
  5687.  struct hostent    *server_hp;
  5688.  struct sockaddr_in bindsock;       /* socket used by bind           */
  5689.  struct sockaddr_in consock;        /* socket used by connect        */
  5690.  int                bindsocklen;    /* size of bind socket           */
  5691.  int                consocklen;     /* size of connect socket        */
  5692.  int                bindrc;         /* the return code from bind     */
  5693.  int                connrc;         /* the return code from connect  */
  5694.  int                ip_part_1;
  5695.  int                ip_part_2;
  5696.  int                ip_part_3;
  5697.  int                ip_part_4;
  5698.  char               tempdsn[L_tmpnam];
  5699.  
  5700.  if (sp->connected_to_server) {
  5701.    GGMdisc(gp,sp);         /* Disconnect from gopher server */
  5702.  }
  5703.  
  5704.  sp->closing_connection = FALSE;
  5705.  sp->buf_index          = -1;
  5706.  sp->bytes_returned     = 0;
  5707.  sp->receiving_text     = FALSE;
  5708.  sp->is_ftp             = FALSE;
  5709.  
  5710.  if (!*gp->ggserver) {
  5711.    ERR1(
  5712.   "No host server defined in Gopher menu,  Cannot make a connection."
  5713.        );
  5714.    return FALSE;
  5715.  }
  5716.  
  5717.  uppercase_in_place(gp->ggserver);
  5718.  
  5719.  /* If server is "local hack", then establish local mode,
  5720.   * open temporary file and return.
  5721.   */
  5722.  
  5723.  if (!strcmp(gp->ggserver, LOCAL_HOST_FROB)) {
  5724.  
  5725.    if (gp->ginfo->port != GOPHER_PORT_NUMBER) {
  5726.      ERR3("Server name %s is permitted only with port number %d.",
  5727.           LOCAL_HOST_FROB, GOPHER_PORT_NUMBER);
  5728.      return FALSE;
  5729.    }
  5730.  
  5731.    GETMAIN(gp->recvp, struct recvstruct, 1, "local recv struct");
  5732.    if (!gp->recvp) {
  5733.      CRIT1("Can't get memory for local host struct");
  5734.      return FALSE;
  5735.    }
  5736.    R = gp->recvp;
  5737.    memset(R, 0, sizeof(struct recvstruct));
  5738.  
  5739.    R->myport   = gp->myport;
  5740.    R->mytelnet = gp->mytelnet;
  5741.    R->mydomain = gp->mydomain;
  5742.  
  5743.    if (!tmpnam(tempdsn)) {
  5744.      CRIT1("Can't create temporary file for local access");
  5745.      return FALSE;
  5746.    }
  5747.  
  5748.    /* Create temporary file for writing and reading. */
  5749.  
  5750.    R->outfp = fopen(tempdsn,"w+,type=memory");
  5751.    if (!R->outfp) {
  5752.      perror(tempdsn);
  5753.      CRIT1("Can't open temporary file for local access");
  5754.      return FALSE;
  5755.    }
  5756.  
  5757.    sp->connected_to_server = TRUE;
  5758.    sp->time_to_go_home     = FALSE;
  5759.    sp->connection_broken   = FALSE;
  5760.  
  5761.    GGMesrvr(gp,sp);
  5762.  
  5763.    return TRUE;
  5764.  }
  5765.  
  5766.  /* Disallow network connections if started up in local mode. */
  5767.  
  5768.  if (gp->local_mode) {
  5769.    ERR1("Network connections are not allowed in local mode.");
  5770.    return FALSE;
  5771.  }
  5772.  
  5773.  /* Determine the local path name. Do only if making net conn. */
  5774.  
  5775.  if (!*gp->client_hostname) {
  5776.  
  5777.    if (!get_client_hostname(gp)) return FALSE;
  5778.  
  5779.  }
  5780.  
  5781.  /* Get server name and address.  */
  5782.  
  5783.  if (strchr(gp->ggserver,'.') &&
  5784.      gp->ggserver[strspn(gp->ggserver,".0123456789")] == '\0') {
  5785.    ip_part_1 = ip_part_2 = ip_part_3 = ip_part_4 = 32767;
  5786.    strcpy(gp->server_hostname, gp->ggserver);
  5787.    strcpy(sp->server_hostname, gp->ggserver);
  5788.    sscanf(gp->ggserver,"%d.%d.%d.%d",&ip_part_1,
  5789.                                      &ip_part_2,
  5790.                                      &ip_part_3,
  5791.                                      &ip_part_4);
  5792.    if (ip_part_1 > 255 ||
  5793.        ip_part_2 > 255 ||
  5794.        ip_part_3 > 255 ||
  5795.        ip_part_4 > 255) {
  5796.      ERR2("Syntax error in server network address: %s", gp->ggserver);
  5797.      return FALSE;
  5798.    }
  5799.    gp->server_ip_address = (IPADDRESS) ((ip_part_1 << 24) +
  5800.                                         (ip_part_2 << 16) +
  5801.                                         (ip_part_3 <<  8) +
  5802.                                         (ip_part_4      ));
  5803.  }
  5804.  else {
  5805.    server_hp = gethostbyname(gp->ggserver);
  5806.    if (!server_hp) {
  5807.      ERR2(
  5808. "Unknown host %s - gethostbyname() could not resolve the server name.",
  5809.           gp->ggserver);
  5810.      return FALSE;
  5811.    }
  5812.    strcpy(gp->server_hostname, server_hp->h_name);
  5813.    strcpy(sp->server_hostname, server_hp->h_name);
  5814.    gp->server_ip_address = *(IPADDRESS *)server_hp->h_addr;
  5815.  }
  5816.  
  5817.  format_ip_address(gp->server_ip_address, gp->server_ip_addrstr);
  5818.  format_ip_address(gp->client_ip_address, gp->client_ip_addrstr);
  5819.  
  5820.  (void)GGMivput(gp,"GGSERVER ",gp->ggserver,-1);
  5821.  (void)GGMivput(gp,"GGSERVIP ",gp->server_ip_addrstr,-1);
  5822.  (void)GGMivput(gp,"GGCLIENT ",gp->ggclient,-1);
  5823.  (void)GGMivput(gp,"GGCLIEIP ",gp->client_ip_addrstr,-1);
  5824.  
  5825.  consock.sin_family       = AF_INET;
  5826.  consock.sin_port         = htons(gp->ginfo->port);
  5827.  consock.sin_addr.s_addr  = gp->server_ip_address;
  5828.  
  5829.  bindsock.sin_family      = AF_INET;
  5830.  bindsock.sin_port        = 0;
  5831. #ifdef SNSTCPIP
  5832.  bindsock.sin_addr.s_addr = INADDR_ANY;
  5833. #else
  5834.  bindsock.sin_addr.s_addr = gp->client_ip_address;
  5835. #endif
  5836.  
  5837.  sp->ns = socket(AF_INET, SOCK_STREAM, 0);
  5838.  if (sp->ns < 0) {
  5839.    REPORT_TCP_ERROR(gp->ggserver);
  5840.    ERR2("TCP/IP error: socket() failed to make socket for server %s.",
  5841.         gp->ggserver);
  5842.    return FALSE;
  5843.  }
  5844.  
  5845.  bindsocklen = sizeof(bindsock);
  5846.  bindrc = Bind(sp->ns, &bindsock, bindsocklen);
  5847.  if (bindrc < 0) {
  5848.    REPORT_TCP_ERROR(gp->ggserver);
  5849.    ERR3("TCP/IP error: bind() failed for socket %d, client IP %8.8x\n",
  5850.         sp->ns, bindsock.sin_addr.s_addr);
  5851.    return FALSE;
  5852.  }
  5853.  
  5854.  (void)GGMispf(gp,"CONTROL DISPLAY LOCK");
  5855.  (void)GGMispf(gp,"DISPLAY PANEL(GGMLCONN)");
  5856.  
  5857.  if (gp->debug_file) {
  5858.    fprintf(gp->debug_file,
  5859.            "Client %s (%s) connecting to GOPHER server on %s (%s)\n",
  5860.            gp->client_hostname,
  5861.            gp->client_ip_addrstr,
  5862.            gp->server_hostname,
  5863.            gp->server_ip_addrstr);
  5864.  }
  5865.  
  5866.  consocklen = sizeof(consock);
  5867.  connrc = Connect(sp->ns, &consock, consocklen);
  5868.  
  5869.  if (connrc < 0) {
  5870.    REPORT_TCP_ERROR(gp->ggserver);
  5871.    ERR2("TCP/IP failure: connect() failed to connect to server %s.",
  5872.         gp->ggserver);
  5873.    return FALSE;
  5874.  }
  5875.  
  5876.  sp->connected_to_server = TRUE;
  5877.  sp->time_to_go_home     = FALSE;
  5878.  sp->connection_broken   = FALSE;
  5879.  sp->server_has_something_pending = TRUE;
  5880.  sp->dont_read           = FALSE;
  5881.  
  5882.  /* Clean up any stray responses from server. */
  5883.  
  5884.  GGMesrvr(gp,sp);                         /* End server read */
  5885.  
  5886.  return TRUE;
  5887.  
  5888. }
  5889.  
  5890. ./ ADD NAME=GGMCSO
  5891.  
  5892.  /********************************************************************/
  5893.  /*                                                                  */
  5894.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  5895.  /*                                                                  */
  5896.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  5897.  /*                                                                  */
  5898.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  5899.  /* including the implied warranties of merchantability and fitness, */
  5900.  /* are expressly denied.                                            */
  5901.  /*                                                                  */
  5902.  /* Provided this copyright notice is included, this software may    */
  5903.  /* be freely distributed and not offered for sale.                  */
  5904.  /*                                                                  */
  5905.  /* Changes or modifications may be made and used only by the maker  */
  5906.  /* of same, and not further distributed.  Such modifications should */
  5907.  /* be mailed to the author for consideration for addition to the    */
  5908.  /* software and incorporation in subsequent releases.               */
  5909.  /*                                                                  */
  5910.  /********************************************************************/
  5911.  
  5912. #pragma  csect(code,  "GG@CSO")
  5913. #pragma  csect(static,"GG$CSO")
  5914. #include "gg.h"
  5915.  
  5916.  /********************************************************************
  5917.   *
  5918.   * The CSO code is due to:
  5919.   *
  5920.   * Lou Joseph     <cwmy5c@irishmvs.cc.nd.edu>
  5921.   * Rachna Agrawal <rachna@clemson.clemson.edu>
  5922.   *
  5923.   ********************************************************************/
  5924.  
  5925. /****** Gopher CSO interface. ************************************/
  5926.  
  5927. Bool
  5928. GGMcso(gp,ip,as_file)
  5929. Rstruc ggcb        *gp;
  5930. Rstruc gopherinfo  *ip;
  5931. GOHOW               as_file;        /* ignored */
  5932. {
  5933.  Rstruc connection *sp;
  5934.  char              *lp;
  5935.  char              *rdel = ":";
  5936.  char              *rtoken;
  5937.  char              *rtok[5];
  5938.  char              *rstr[14];
  5939.  int                a;              /* field counter */
  5940.  int                b;              /* field counter */
  5941.  int                c;              /* field counter */
  5942.  int                d;              /* field counter */
  5943.  int                e_index_i;
  5944.  Bool               got_some;
  5945.  char               ggcsoq[14][256];
  5946.  char               e_index_c[10];
  5947.  char               sep[80] = "--------------------";
  5948.  
  5949.  sp = &gp->gopher_connection;
  5950.  
  5951.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  5952.  
  5953.  /***** set up fields command to server ***** start ******************/
  5954.  
  5955.  strcpy(gp->gopher_command,"fields");
  5956.  
  5957.  /***** set up fields command to server ***** end   ******************/
  5958.  
  5959.  gp->ginfo = ip;
  5960.  
  5961.  if (!GGMconn(gp,sp)) return FALSE;   /* Connect to CSO server */
  5962.  
  5963.  GOPHERSEND(gp,sp);                   /* Send socket command */
  5964.  
  5965.  GGMclrtx(gp,ip);                  /* Clear text */
  5966.  
  5967.  for (d = 0; d < 4;  d++) rtok[d] = "";
  5968.  for (d = 0; d < 14; d++) rstr[d] = "";
  5969.  
  5970.  sp->receiving_text = TRUE;
  5971.  got_some = FALSE;
  5972.  a = 0;           /* controls that each field is output only once */
  5973.  b = 0;           /* counts the server line */
  5974.  c = 0;           /* counts number of tokens in each new line */
  5975.  d = 0;           /* counts that only some of the fields are saved */
  5976.  do {
  5977.    if (GGMgsrvl(gp,sp,&lp,FALSE)) {             /* Get server line  */
  5978.      if (lp) {
  5979.        ++b;
  5980.        if (b == 2) {
  5981.           a = 1;
  5982.           b = 0;
  5983.        }      /* end if  (b == 2) */
  5984.        if (a == 1) {                              /* if new entry */
  5985.           c = 0;
  5986.           rtoken = strtok(lp,rdel);
  5987.           while (rtoken != NULL) {
  5988.               rtok[c] = rtoken;
  5989.               ++c;
  5990.               rtoken = strtok(NULL,rdel);
  5991.           }      /* end while  */
  5992.           a = 0;
  5993.           if (d < 14)  {
  5994.             GETMAIN(rstr[d],char,strlen(rtok[2]+1),"CSO field string");
  5995.             if (!rstr[d]) break;
  5996.             strcpy(rstr[d], rtok[2]);
  5997.             ++d;
  5998.           }
  5999.        }    /* end if new entry */
  6000.        got_some = TRUE;
  6001.        if (lp[0] != '-' && strncmp(lp,"200",3) >= 0) break;
  6002.      }        /* end if lp */
  6003.    }      /* end if GGMgsrvl */
  6004.  } while (lp);                            /* until no more lines */
  6005.  
  6006.  if (!got_some) {
  6007.    WARN2("No data available from server %s.\n",gp->ggserver);
  6008.    return FALSE;
  6009.  }
  6010.  
  6011.  sp->receiving_text = FALSE;
  6012.  
  6013.  /*************************** GGMivput **********************/
  6014.  GGMivput(gp,"FNAME1 ",rstr[0],strlen(rstr[0]));
  6015.  GGMivput(gp,"FNAME2 ",rstr[1],strlen(rstr[1]));
  6016.  GGMivput(gp,"FNAME3 ",rstr[2],strlen(rstr[2]));
  6017.  GGMivput(gp,"FNAME4 ",rstr[3],strlen(rstr[3]));
  6018.  GGMivput(gp,"FNAME5 ",rstr[4],strlen(rstr[4]));
  6019.  GGMivput(gp,"FNAME6 ",rstr[5],strlen(rstr[5]));
  6020.  GGMivput(gp,"FNAME7 ",rstr[6],strlen(rstr[6]));
  6021.  GGMivput(gp,"FNAME8 ",rstr[7],strlen(rstr[7]));
  6022.  GGMivput(gp,"FNAME9 ",rstr[8],strlen(rstr[8]));
  6023.  GGMivput(gp,"FNAME10 ",rstr[9],strlen(rstr[9]));
  6024.  GGMivput(gp,"FNAME11 ",rstr[10],strlen(rstr[10]));
  6025.  GGMivput(gp,"FNAME12 ",rstr[11],strlen(rstr[11]));
  6026.  GGMivput(gp,"FNAME13 ",rstr[12],strlen(rstr[12]));
  6027.  GGMivput(gp,"FNAME14 ",rstr[13],strlen(rstr[13]));
  6028.  /*************************** GGMivput **********************/
  6029.  
  6030.  GGMispf(gp,"VGET (FVALUE1) PROFILE");
  6031.  
  6032.  if (GGMdispl(gp,"GGMCSO  ") > 0) return FALSE;
  6033.  
  6034.  /*************************** GGMivget **********************/
  6035.  GGMivget(gp,"FVALUE1 ",ggcsoq[0], sizeof(ggcsoq[0]));
  6036.  GGMivget(gp,"FVALUE2 ",ggcsoq[1], sizeof(ggcsoq[1]));
  6037.  GGMivget(gp,"FVALUE3 ",ggcsoq[2], sizeof(ggcsoq[2]));
  6038.  GGMivget(gp,"FVALUE4 ",ggcsoq[3], sizeof(ggcsoq[3]));
  6039.  GGMivget(gp,"FVALUE5 ",ggcsoq[4], sizeof(ggcsoq[4]));
  6040.  GGMivget(gp,"FVALUE6 ",ggcsoq[5], sizeof(ggcsoq[5]));
  6041.  GGMivget(gp,"FVALUE7 ",ggcsoq[6], sizeof(ggcsoq[6]));
  6042.  GGMivget(gp,"FVALUE8 ",ggcsoq[7], sizeof(ggcsoq[7]));
  6043.  GGMivget(gp,"FVALUE9 ",ggcsoq[8], sizeof(ggcsoq[8]));
  6044.  GGMivget(gp,"FVALUE10 ",ggcsoq[9], sizeof(ggcsoq[9]));
  6045.  GGMivget(gp,"FVALUE11 ",ggcsoq[10], sizeof(ggcsoq[10]));
  6046.  GGMivget(gp,"FVALUE12 ",ggcsoq[11], sizeof(ggcsoq[11]));
  6047.  GGMivget(gp,"FVALUE13 ",ggcsoq[12], sizeof(ggcsoq[12]));
  6048.  GGMivget(gp,"FVALUE14 ",ggcsoq[13], sizeof(ggcsoq[13]));
  6049.  /*************************** GGMivget **********************/
  6050.  
  6051.  /***** set up query command to server ****** start ******************/
  6052.  strcpy(gp->gopher_command,"query ");
  6053.  if (!*ip->path) {
  6054.     for (a = 0; a < 14; a++)
  6055.         if (strlen(ggcsoq[a]) != 0) {
  6056.            strcat(gp->gopher_command + 6, rstr[a]);
  6057.            strcat(gp->gopher_command, "=\"");
  6058.            strcat(gp->gopher_command, ggcsoq[a]);
  6059.            strcat(gp->gopher_command, "\" ");
  6060.         }
  6061.  }
  6062.  else {
  6063.     sprintf(gp->gopher_command + 6,"%s\t",ip->path);
  6064.     for (a = 0; a < 14; a++) {
  6065.         strcat(gp->gopher_command + 6, rstr[a]);
  6066.         strcat(gp->gopher_command," =\"");
  6067.         strcat(gp->gopher_command, ggcsoq[a]);
  6068.         strcat(gp->gopher_command, "\" ");
  6069.     }
  6070.  }
  6071.  strcat(gp->gopher_command," return all");
  6072.  
  6073.  /***** set up query command to server ******* end *******************/
  6074.  
  6075.  GOPHERSEND(gp,sp);                   /* Send socket command */
  6076.  
  6077.  GGMclrtx(gp,ip);                  /* Clear text */
  6078.  
  6079.  sp->receiving_text = TRUE;
  6080.  got_some = FALSE;
  6081.  e_index_i = 2;
  6082.  sprintf(e_index_c,":%u:",e_index_i);
  6083.  do {
  6084.    if (GGMgsrvl(gp,sp,&lp,FALSE)) {        /* Get server line */
  6085.      if (lp) {
  6086.        if (strstr(lp,e_index_c) != NULL) { /* if new entry */
  6087.          (void)GGMouttx(gp,sep,ip);        /* Output separator */
  6088.          ++e_index_i;                      /* Increment index  */
  6089.          sprintf(e_index_c,":%u:",e_index_i);
  6090.        }
  6091.        got_some = TRUE;
  6092.        (void)GGMouttx(gp,lp,ip);          /* Output text line */
  6093.        if (lp[0] != '-' && strncmp(lp,"200",3) >= 0) break;
  6094.      }
  6095.    }
  6096.  } while (lp);                            /* until no more lines */
  6097.  
  6098.  if (!got_some) {
  6099.    WARN2("No data available from server %s.\n",gp->ggserver);
  6100.    return FALSE;
  6101.  }
  6102.  
  6103.  /* Send quit command        */
  6104.  
  6105.  sp->receiving_text = FALSE;
  6106.  
  6107.  strcpy(gp->gopher_command,"quit");
  6108.  
  6109.  GOPHERSEND(gp,sp);                   /* Send socket command */
  6110.  
  6111.  /* Read Bye message         */
  6112.  
  6113.  sp->receiving_text = TRUE;
  6114.  
  6115.  (void)GGMgsrvl(gp,sp,&lp,FALSE);         /* Get server line */
  6116.  
  6117.  if (sp->connected_to_server) {
  6118.    (void)GGMdisc(gp,sp);   /* Disconnect from CSO server */
  6119.  }
  6120.  
  6121.  GGMvtx(gp,ip,as_file);  /* display text from CSO server */
  6122.  
  6123.  for (d = 0; d < 14; d++) {
  6124.    if (*rstr[d]) {
  6125.      FREEMAIN(rstr[d],"CSO field string");
  6126.    }
  6127.  }
  6128.  
  6129.  return TRUE;
  6130.  
  6131. }
  6132.  
  6133. ./ ADD NAME=GGMDBM
  6134.  
  6135.  /********************************************************************/
  6136.  /*                                                                  */
  6137.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  6138.  /*                                                                  */
  6139.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6140.  /*                                                                  */
  6141.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6142.  /* including the implied warranties of merchantability and fitness, */
  6143.  /* are expressly denied.                                            */
  6144.  /*                                                                  */
  6145.  /* Provided this copyright notice is included, this software may    */
  6146.  /* be freely distributed and not offered for sale.                  */
  6147.  /*                                                                  */
  6148.  /* Changes or modifications may be made and used only by the maker  */
  6149.  /* of same, and not further distributed.  Such modifications should */
  6150.  /* be mailed to the author for consideration for addition to the    */
  6151.  /* software and incorporation in subsequent releases.               */
  6152.  /*                                                                  */
  6153.  /********************************************************************/
  6154.  
  6155. #pragma  csect(code,  "GG@DBM  ")
  6156. #pragma  csect(static,"GG$DBM  ")
  6157. #include "gg.h"
  6158.  
  6159. /****** Delete a bookmark from a bookmark data set. ******************/
  6160.  
  6161. Bool
  6162. GGMdbm(gp,ip)
  6163. Rstruc ggcb         *gp;
  6164. Rstruc gopherinfo   *ip;
  6165. {
  6166.  FILE               *xfp;
  6167.  char               *bufptr;
  6168.  char                test   [  6];
  6169.  char                dsname [129];
  6170.  char                buffer [RBUFSIZE];
  6171.  
  6172.  if (!*ip->bmds) {
  6173.    WARN1("Delete not possible.  This entry is not from a bookmark.");
  6174.    return FALSE;
  6175.  }
  6176.  
  6177.  GGMivput(gp,"GGMDBMDS ",ip->bmds,-1);
  6178.  GGMivput(gp,"GGMDBMSU ",ip->desc,-1);
  6179.  
  6180.  (void)GGMispf(gp,"ADDPOP");
  6181.  
  6182.  if (GGMdispl(gp,"GGMPDBM ") > 0) {
  6183.    WARN1("Deletion cancelled, because you pressed END.");
  6184.    (void)GGMispf(gp,"REMPOP");
  6185.    return FALSE;
  6186.  }
  6187.  
  6188.  (void)GGMispf(gp,"REMPOP");
  6189.  
  6190.  sprintf(dsname,"'%s'",ip->bmds);
  6191.  xfp = fopen(dsname,"r");
  6192.  if (!xfp) {
  6193.    perror(dsname);
  6194.    ERR2("Cannot access bookmark data set %s.",dsname);
  6195.    return FALSE;
  6196.  }
  6197.  
  6198.  
  6199.  for (;;) {
  6200.    *buffer = '\0';
  6201.    fgets(buffer,sizeof(buffer),xfp);
  6202.    if (ferror(xfp)) {
  6203.      ERR2("Error reading bookmark data set %s.",dsname);
  6204.      break;
  6205.    }
  6206.    if (feof(xfp)) break;
  6207.    if ((bufptr=strchr(buffer,'\n'))) *bufptr = '\0';
  6208.    bufptr = skip_whitespace(buffer);
  6209.    memset(test,0,sizeof(test));
  6210.    memcpy(test,bufptr,5);
  6211.    uppercase_in_place(test);
  6212.  
  6213.    /*
  6214.    if      (EQUAL(test,"TYPE="))
  6215.    else if (EQUAL(test,"NAME="))
  6216.    else if (EQUAL(test,"PATH="))
  6217.    else if (EQUAL(test,"HOST="))
  6218.    else if (EQUAL(test,"PORT="))
  6219.    else if (EQUAL(test,"END"  ))
  6220.  
  6221.    */
  6222.  
  6223.  }
  6224.  
  6225.  (void)fclose(xfp);
  6226.  
  6227.  ERR1("Bookmark deletion is not yet supported, sorry.");
  6228.  return FALSE;
  6229.  
  6230. }
  6231.  
  6232. ./ ADD NAME=GGMDFAIL
  6233.  
  6234.  /********************************************************************/
  6235.  /*                                                                  */
  6236.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  6237.  /*                                                                  */
  6238.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6239.  /*                                                                  */
  6240.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6241.  /* including the implied warranties of merchantability and fitness, */
  6242.  /* are expressly denied.                                            */
  6243.  /*                                                                  */
  6244.  /* Provided this copyright notice is included, this software may    */
  6245.  /* be freely distributed and not offered for sale.                  */
  6246.  /*                                                                  */
  6247.  /* Changes or modifications may be made and used only by the maker  */
  6248.  /* of same, and not further distributed.  Such modifications should */
  6249.  /* be mailed to the author for consideration for addition to the    */
  6250.  /* software and incorporation in subsequent releases.               */
  6251.  /*                                                                  */
  6252.  /********************************************************************/
  6253.  
  6254. #pragma  csect(code,  "GG@DFAIL")
  6255. #pragma  csect(static,"GG$DFAIL")
  6256. #include "gg.h"
  6257.  
  6258. /****** Retrieve allocation failure messages. ************************/
  6259.  
  6260. void
  6261. GGMdfail(rc,p99)
  6262. int            rc;
  6263. __S99parms    *p99;
  6264. {
  6265.  int           zero = 0;
  6266.  unsigned int  dfid = 0x40320000;
  6267.  struct {
  6268.          short first_level_msg_len;
  6269.          short first_level_msg_offset;
  6270.          char  first_level_msg[251];
  6271.          short second_level_msg_len;
  6272.          short second_level_msg_offset;
  6273.          char  second_level_msg[251];
  6274.         }      dfbuffer;
  6275.  
  6276.  static int (*ikjeff18_pointer)() = NULL;
  6277.  
  6278. #ifndef FETCH
  6279.  extern int *ikjeff18();
  6280. #endif
  6281.  
  6282.  if (!ikjeff18_pointer) {
  6283. #ifdef FETCH
  6284.    ikjeff18_pointer = (int (*)())fetch("IKJEFF18");
  6285. #else
  6286.    ikjeff18_pointer = (int (*)())ikjeff18;
  6287. #endif
  6288.  }
  6289.  
  6290.  dfbuffer.first_level_msg_len = 4;
  6291.  dfbuffer.second_level_msg_len = 4;
  6292.  
  6293.  if (ikjeff18_pointer) {
  6294.    if ((*ikjeff18_pointer)(p99,&rc,&zero,&dfid,&zero,&dfbuffer)) {
  6295.      fprintf(stderr,"IKJEFF18 returned a nonzero return code\n");
  6296.    }
  6297.    if (dfbuffer.first_level_msg_len > 0) {
  6298.      fprintf(stderr,"%*.*s\n",
  6299.                     dfbuffer.first_level_msg_len-4,
  6300.                     dfbuffer.first_level_msg_len-4,
  6301.                     dfbuffer.first_level_msg);
  6302.    }
  6303.    if (dfbuffer.second_level_msg_len > 0) {
  6304.      fprintf(stderr,"%*.*s\n",
  6305.                     dfbuffer.second_level_msg_len-4,
  6306.                     dfbuffer.second_level_msg_len-4,
  6307.                     dfbuffer.second_level_msg);
  6308.    }
  6309.  }
  6310.  else {
  6311. #ifdef FETCH
  6312.    fprintf(stderr,"GGMVS: Cannot fetch IKJEFF18\n");
  6313. #else
  6314.    fprintf(stderr,"Cannot call IKJEFF18, not linked with GGMVS\n");
  6315. #endif
  6316.  }
  6317.  return;
  6318. }
  6319.  
  6320. ./ ADD NAME=GGMDIR
  6321.  
  6322.  /********************************************************************/
  6323.  /*                                                                  */
  6324.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  6325.  /*                                                                  */
  6326.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6327.  /*                                                                  */
  6328.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6329.  /* including the implied warranties of merchantability and fitness, */
  6330.  /* are expressly denied.                                            */
  6331.  /*                                                                  */
  6332.  /* Provided this copyright notice is included, this software may    */
  6333.  /* be freely distributed and not offered for sale.                  */
  6334.  /*                                                                  */
  6335.  /* Changes or modifications may be made and used only by the maker  */
  6336.  /* of same, and not further distributed.  Such modifications should */
  6337.  /* be mailed to the author for consideration for addition to the    */
  6338.  /* software and incorporation in subsequent releases.               */
  6339.  /*                                                                  */
  6340.  /********************************************************************/
  6341.  
  6342. #pragma  csect(code,  "GG@DIR  ")
  6343. #pragma  csect(static,"GG$DIR  ")
  6344. #include "gg.h"
  6345.  
  6346. /*********************************************************************/
  6347.  
  6348. static Bool
  6349. valid_code(c)
  6350. char       c;
  6351. {
  6352.  
  6353.  switch (c) {
  6354.    case GOPHER_FILE:
  6355.    case GOPHER_DIRECTORY:
  6356.    case GOPHER_TELNET:
  6357.    case GOPHER_TN3270:
  6358.    case GOPHER_WAIS:
  6359.    case GOPHER_WHOIS:
  6360.    case GOPHER_CSO:
  6361.                            return TRUE;
  6362.    default:                return FALSE;
  6363.   }
  6364.  
  6365. }
  6366.  
  6367. /*********************************************************************/
  6368.  
  6369. static Bool
  6370. process_s_selection(gp,ip)
  6371. Rstruc ggcb           *gp;
  6372. Rstruc gopherinfo     *ip;
  6373. {
  6374.  
  6375.  GGMgofor(gp,ip,AS_NORMAL);
  6376.  
  6377.  return TRUE;
  6378. }
  6379.  
  6380. /*********************************************************************/
  6381.  
  6382. static Bool
  6383. process_i_selection(gp,ip)
  6384. Rstruc ggcb           *gp;
  6385. Rstruc gopherinfo     *ip;
  6386. {
  6387.  
  6388.  if (!GGMinfo(gp,ip)) return FALSE;
  6389.  
  6390.  GGMvtx(gp,NULL,AS_FILE);
  6391.  
  6392.  return TRUE;
  6393. }
  6394.  
  6395. /*********************************************************************/
  6396.  
  6397. static Bool
  6398. process_b_selection(gp,ip)
  6399. Rstruc ggcb           *gp;
  6400. Rstruc gopherinfo     *ip;
  6401. {
  6402.  
  6403.  if (!GGMinfo(gp,ip)) return FALSE;
  6404.  
  6405.  gp->extract_file = NULL;
  6406.  
  6407.  GGMxtx(gp,ip,BOOKMARK_IT);
  6408.  
  6409.  return TRUE;
  6410. }
  6411.  
  6412. /*********************************************************************/
  6413.  
  6414. static Bool
  6415. process_d_selection(gp,ip)
  6416. Rstruc ggcb           *gp;
  6417. Rstruc gopherinfo     *ip;
  6418. {
  6419.  
  6420.  return GGMdbm(gp,ip);
  6421. }
  6422.  
  6423. /*********************************************************************/
  6424.  
  6425. static Bool
  6426. process_e_selection(gp,ip)
  6427. Rstruc ggcb           *gp;
  6428. Rstruc gopherinfo     *ip;
  6429. {
  6430.  
  6431.  if (!ip->thdr.first_text_line) {
  6432.    GGMgofor(gp,ip,AS_NOTHING);
  6433.  }
  6434.  
  6435.  if (!ip->thdr.first_text_line) return FALSE;
  6436.  gp->extract_file = NULL;
  6437.  GGMxtx(gp,ip,EXTRACT_IT);
  6438.  return TRUE;
  6439. }
  6440.  
  6441. /*********************************************************************/
  6442.  
  6443. static Bool
  6444. process_p_selection(gp,ip)
  6445. Rstruc ggcb           *gp;
  6446. Rstruc gopherinfo     *ip;
  6447. {
  6448.  
  6449.  if (!ip->thdr.first_text_line) {
  6450.    GGMgofor(gp,ip,AS_NOTHING);
  6451.  }
  6452.  
  6453.  if (!ip->thdr.first_text_line) return FALSE;
  6454.  gp->extract_file = NULL;
  6455.  GGMxtx(gp,ip,PRINT_IT);
  6456.  return TRUE;
  6457. }
  6458.  
  6459. /*********************************************************************/
  6460.  
  6461. static Bool
  6462. process_q_selection(gp,ip)
  6463. Rstruc ggcb           *gp;
  6464. Rstruc gopherinfo     *ip;
  6465. {
  6466.  
  6467.  GGMgofor(gp,ip,AS_FILE);
  6468.  
  6469.  return TRUE;
  6470. }
  6471.  
  6472. /*********************************************************************/
  6473.  
  6474. static Bool
  6475. display_dynamic_area(gp,ip,infoarray,entrycount)
  6476. Rstruc ggcb           *gp;
  6477. Rstruc gopherinfo     *ip;
  6478. Rstruc gopherinfo     *infoarray;
  6479. int                    entrycount;
  6480. {
  6481.  struct gopherinfo    *iap;
  6482.  int                   depth;
  6483.  int                   ggglvl;
  6484.  int                   dynsize;
  6485.  int                   topitem;
  6486.  int                   bottomitem;
  6487.  int                   last_item_selected;
  6488.  int                   dti;
  6489.  int                   gii;
  6490.  int                   l;
  6491.  int                   prc;
  6492.  int                   command_index;
  6493.  int                   zscrolln;
  6494.  int                   leftcol;
  6495.  int                   maxcol;
  6496.  int                   menucursor;
  6497.  Bool                  selection_processed_ok;
  6498.  Bool                  command_processed_ok;
  6499.  Bool                  is_max;
  6500.  Bool                  is_csr;
  6501.  char                 *gggdyna;
  6502.  char                 *rowp;
  6503.  char                 *cp;
  6504.  char                  gggcmd     [72];
  6505.  char                  zverb       [9];
  6506.  char                  zscrolla    [9];
  6507.  char                  command    [COMMANDSIZE];
  6508.  char                  ggghead    [81];
  6509.  char                  gggcsr     [12];
  6510.  char                  rowmessage [81];
  6511.  
  6512.  /* Get depth of dynamic area (number of rows to display on screen) */
  6513.  
  6514.  (void)GGMispf(gp,
  6515.        "PQUERY PANEL(GGMDIR) AREANAME(GGGDYNA) DEPTH(GGGDEPTH)");
  6516.  if (gp->ispfrc != 0) return FALSE;
  6517.  depth = GGMiget(gp,"GGGDEPTH ");
  6518.  
  6519.  /* Get storage for ISPF dynamic area variable to be constructed. */
  6520.  
  6521.  dynsize = 80*depth;
  6522.  GETMAIN(gggdyna, char, dynsize+1, "GGGDYNA buffer");
  6523.  if (!gggdyna) return FALSE;
  6524.  
  6525.  /* Loop displaying the panel until END pressed. */
  6526.  
  6527.  topitem = 0;
  6528.  leftcol = 0;
  6529.  menucursor = 0;
  6530.  last_item_selected = -1;
  6531.  strcpy(gggcmd,"");
  6532.  
  6533.  maxcol = 0;
  6534.  for (gii = 0; gii < entrycount; gii++) {
  6535.    l = strlen(infoarray[gii].desc);
  6536.    if (maxcol < l) maxcol = l;
  6537.  }
  6538.  
  6539.  do {
  6540.  
  6541.  /* Fill in the dynamic area with rows, one for each gopher item. */
  6542.  
  6543.    memset(gggdyna,' ',dynsize);
  6544.    menucursor = 0;
  6545.  
  6546.    for (dti = 0,       gii = topitem,     rowp = gggdyna;
  6547.         dti < depth && gii < entrycount;
  6548.         dti++,         gii++,             rowp += 80) {
  6549.      iap = &infoarray[gii];
  6550.      if (gp->autocursor && gii == last_item_selected) {
  6551.        menucursor = rowp + 2 - gggdyna;
  6552.      }
  6553.      rowp[ 0] = DATAIN_HIGH;             /* selection code attribute */
  6554.      rowp[ 1] = ' ';                     /* selection code field     */
  6555.      rowp[ 2] = DATAOUT_GREEN;           /* icon attribute           */
  6556.      memcpy(&rowp[ 3],GGMtype(iap->type),9);
  6557.      rowp[12] = DATAOUT_HIGH;            /* description attribute    */
  6558.      l = strlen(iap->desc) - leftcol;
  6559.      if (l > 0) {
  6560.        memcpy(&rowp[13], iap->desc + leftcol, l > 67 ? 67 : l);
  6561.      }
  6562.    }
  6563.  
  6564.    if (rowp < gggdyna + dynsize) {
  6565.      rowp[0] = DATAOUT_HIGH;
  6566.      memset(&rowp[1], '-',79);
  6567.    }
  6568.  
  6569.    bottomitem = gii - 1;
  6570.  
  6571.    if (topitem > bottomitem) strcpy(rowmessage,"");
  6572.    else sprintf(rowmessage, " %d-%d of %d",
  6573.                        topitem + 1, bottomitem + 1, entrycount);
  6574.  
  6575.    memset(ggghead,' ',79);
  6576.    ggghead[79] = '\0';
  6577.    strcpy(ggghead,"GOPHER - ");
  6578.    strncpy(ggghead+9,ip->desc,70);
  6579.    *strchr(ggghead,'\0') = ' ';
  6580.    memcpy(ggghead+79-strlen(rowmessage),rowmessage,strlen(rowmessage));
  6581.  
  6582.    if (menucursor > 0) {
  6583.      sprintf(gggcsr,"%d",menucursor);
  6584.      (void)GGMivput(gp,"GGGCSR ", gggcsr, -1);
  6585.    }
  6586.    else {
  6587.      (void)GGMivput(gp,"GGGCSR ", "0", 1);
  6588.    }
  6589.  
  6590.    (void)GGMivput(gp,"GGGHEAD ",ggghead,79);
  6591.    (void)GGMivput(gp,"GGGDYNA ",gggdyna, dynsize);
  6592.    (void)GGMivput(gp,"GGGCMD " ,gggcmd,  -1);
  6593.  
  6594.    prc = GGMdispl(gp,"GGMDIR  ");
  6595.    if (prc > 8) break;
  6596.  
  6597.    (void)GGMivget(gp,"GGGDYNA " , gggdyna,  dynsize);
  6598.    (void)GGMivget(gp,"ZVERB "   , zverb,    sizeof(zverb));
  6599.    (void)GGMivget(gp,"ZSCROLLA ", zscrolla, sizeof(zscrolla));
  6600.    zscrolln = GGMiget(gp,"ZSCROLLN ");
  6601.    ggglvl   = GGMiget(gp,"GGGLVL ");
  6602.    last_item_selected = -1;
  6603.  
  6604.    /* Process selections. */
  6605.  
  6606.    for (gii = topitem,         rowp = gggdyna;
  6607.         gii <= bottomitem;
  6608.         gii++,                 rowp += 80) {
  6609.      iap = &infoarray[gii];
  6610.      switch (toupper(rowp[1])) {
  6611.        case ' ':  continue;
  6612.        case 'S':  selection_processed_ok = process_s_selection(gp,iap);
  6613.                   break;
  6614.        case 'E':  selection_processed_ok = process_e_selection(gp,iap);
  6615.                   break;
  6616.        case 'P':  selection_processed_ok = process_p_selection(gp,iap);
  6617.                   break;
  6618.        case 'Q':  selection_processed_ok = process_q_selection(gp,iap);
  6619.                   break;
  6620.        case 'I':  selection_processed_ok = process_i_selection(gp,iap);
  6621.                   break;
  6622.        case 'B':  selection_processed_ok = process_b_selection(gp,iap);
  6623.                   break;
  6624.    /*
  6625.     *  case 'D':  selection_processed_ok = process_d_selection(gp,iap);
  6626.     *             break;
  6627.     */
  6628.        default:
  6629.         ERR1("Unknown selection code.  Type one of the listed codes.");
  6630.                   selection_processed_ok = FALSE;
  6631.                   break;
  6632.      }
  6633.      if (selection_processed_ok) last_item_selected = gii;
  6634.      if (gp->quit) break;
  6635.    }
  6636.  
  6637.    /* Process command if any. */
  6638.  
  6639.    strcpy(gggcmd,"");
  6640.  
  6641.    (void)GGMivget(gp,"GGGCMD ",gggcmd,sizeof(gggcmd));
  6642.  
  6643.    if (*gggcmd) {
  6644.  
  6645.      command_processed_ok = TRUE;
  6646.      memset(command,' ',COMMANDSIZE);
  6647.      command_index = 0;
  6648.      for (cp = gggcmd; *cp && !isspace(*cp); cp++) {
  6649.        if (cp >= gggcmd+COMMANDSIZE) {
  6650.        ERR1("Invalid command.  Try \"MENU bookmarkname\" or \"QUIT\"");
  6651.          command_processed_ok = FALSE;
  6652.        }
  6653.        command[command_index++] = toupper(*cp);
  6654.      }
  6655.      while (*cp && isspace(*cp)) cp++;
  6656.  
  6657.      if      (!memcmp(command,"QUIT    ",8)) gp->quit = TRUE;
  6658.      else if (!memcmp(command,"MENU    ",8)) GGMmenu(gp,cp);
  6659.      else if (!memcmp(command,"OPT     ",8)
  6660.            || !memcmp(command,"OPTION  ",8)
  6661.            || !memcmp(command,"OPTIONS ",8)) GGMdsopt(gp,cp);
  6662.      else if (!memcmp(command,"TEST    ",8)) {
  6663.                                               gp->test_mode = TRUE;
  6664.                                               __ctest(NULL);
  6665.                                              }
  6666.      else {
  6667.        ERR1(
  6668.  "Unknown command.  Try \"OPTIONS\", \"MENU bookmarkname\", \"QUIT\""
  6669.            );
  6670.        command_processed_ok = FALSE;
  6671.      }
  6672.  
  6673.      if (command_processed_ok) strcpy(gggcmd,"");
  6674.  
  6675.    }
  6676.  
  6677.    if (gp->quit) break;
  6678.  
  6679.    if (last_item_selected >= 0 && gp->autoscroll) {
  6680.      topitem = last_item_selected;
  6681.    }
  6682.  
  6683.    /* Process scroll request if any. */
  6684.  
  6685.    is_max = EQUAL(zscrolla,"MAX");
  6686.    is_csr = zscrolla[0] == 'C';
  6687.    if      (EQUAL(zverb,"DOWN")) {
  6688.      if (is_max) topitem = entrycount - ggglvl;
  6689.      else        topitem += zscrolln;
  6690.    }
  6691.    else if (EQUAL(zverb,"UP")) {
  6692.      if (is_max) topitem = 0;
  6693.      else        topitem -= zscrolln;
  6694.    }
  6695.    else if (EQUAL(zverb,"LEFT")) {
  6696.      if (is_max) leftcol = 0;
  6697.      else        leftcol -= zscrolln;
  6698.    }
  6699.    else if (EQUAL(zverb,"RIGHT")) {
  6700.      if (is_csr) zscrolln -= 13;
  6701.      if (is_max) leftcol = maxcol - 67;
  6702.      else        leftcol += zscrolln;
  6703.    }
  6704.    else if (EQUAL(zverb,"RETURN")) {
  6705.      gp->quit = TRUE;
  6706.      break;
  6707.    }
  6708.    if (topitem < 0)          topitem = 0;
  6709.    if (topitem > entrycount) topitem = entrycount;
  6710.    if (leftcol < 0)          leftcol = 0;
  6711.    if (leftcol > maxcol)     leftcol = maxcol;
  6712.  
  6713.  } while (prc == 0);
  6714.  
  6715.  return;
  6716.  
  6717. }
  6718.  
  6719. /****** Gopher a directory. ******************************************/
  6720.  
  6721. Bool
  6722. GGMdir(gp,ip,how)
  6723. Rstruc ggcb        *gp;
  6724. Rstruc gopherinfo  *ip;
  6725. GOHOW               how;
  6726. {
  6727.  int                entrycount;
  6728.  int                i;
  6729.  int                copysize;
  6730.  char               typechar;
  6731.  char               savechar;
  6732.  char              *p;
  6733.  char              *q;
  6734.  char              *r;
  6735.  struct textline   *tp;
  6736.  struct gopherinfo *infoarray;
  6737.  struct gopherinfo *iap;
  6738.  char               temp[16];
  6739.  
  6740.  switch (how) {
  6741.    case AS_FILE:
  6742.                     GGMvtx(gp,ip,AS_FILE);  /* display text as is */
  6743.                     return TRUE;
  6744.    case AS_NOTHING:                         /* prepare for extract */
  6745.                     return TRUE;
  6746.    case AS_NORMAL:
  6747.    default:
  6748.                     break;
  6749.  }
  6750.  
  6751.  /* The text chain contains the data from the server, which should be
  6752.   * in the following format:
  6753.   *
  6754.   * nDescription^Path^foo^bar
  6755.   *
  6756.   * where the "n" in the beginning is a digit and ^ means a tab char.
  6757.   *
  6758.   * Logic:
  6759.   *
  6760.   * Build an array of gopherinfo structs from the text records.
  6761.   *
  6762.   * Display them as an ISPF dynamic area pseudotable.
  6763.   *
  6764.   * Let the user select them, and run GGMgofor on each one
  6765.   * with a struct gopherinfo built from the contents.
  6766.   *
  6767.   */
  6768.  
  6769.  /* Determine size of array of gopherinfo structs.  This is equal to
  6770.   * the number of text records with a valid code in the first byte.
  6771.   */
  6772.  
  6773.  entrycount = 0;
  6774.  for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
  6775.    if (valid_code(tp->text[0])) entrycount++;
  6776.  }
  6777.  
  6778.  if (entrycount == 0) {
  6779.    ERR1("There seems to be no information in this directory.\n");
  6780.    return FALSE;
  6781.  }
  6782.  
  6783.  /* Allocate an array of structs to hold the stuff. */
  6784.  
  6785.  GETMAIN(infoarray, struct gopherinfo, entrycount,"gopherinfo array");
  6786.  
  6787.  if (!infoarray) {
  6788.    ERR2("Not enough memory for %d gopher directory entries\n",
  6789.         entrycount);
  6790.    return FALSE;
  6791.  }
  6792.  
  6793.  /* Build the array entries. */
  6794.  
  6795.  iap = infoarray;
  6796.  for (tp = ip->thdr.first_text_line; tp; tp = tp->next) {
  6797.    typechar = tp->text[0];
  6798.    if (valid_code(typechar)) {
  6799.      r = &tp->text[tp->text_length];
  6800.      savechar = *r;
  6801.      *r = '\t';
  6802.      memset(iap,0,sizeof(struct gopherinfo));
  6803.      iap->port = GOPHER_PORT_NUMBER;
  6804.      iap->type = (gophertype)typechar;
  6805.      p = &tp->text[1];
  6806.      q = strchr(p,'\t');
  6807.      copysize = sizeof(iap->desc)-1;
  6808.      if (copysize > q-p) copysize = q-p;
  6809.      memcpy(iap->desc,p,copysize);
  6810.      if (q < r) {
  6811.        p = q+1;
  6812.        q = strchr(p,'\t');
  6813.        copysize = sizeof(iap->path)-1;
  6814.        if (copysize > q-p) copysize = q-p;
  6815.        memcpy(iap->path,p,copysize);
  6816.        if (q < r) {
  6817.          p = q+1;
  6818.          q = strchr(p,'\t');
  6819.          copysize = sizeof(iap->host)-1;
  6820.          if (copysize > q-p) copysize = q-p;
  6821.          memcpy(iap->host,p,copysize);
  6822.          if (q < r) {
  6823.            p = q+1;
  6824.            q = strchr(p,'\t');
  6825.            memset(temp,0,sizeof(temp));
  6826.            copysize = sizeof(temp)-1;
  6827.            if (copysize > q-p) copysize = q-p;
  6828.            memcpy(temp,p,copysize);
  6829.            iap->port = atoi(temp);
  6830.          }
  6831.        }
  6832.      }
  6833.  
  6834.      strcpy(iap->bmds,gp->current_bookmark_ds);
  6835.  
  6836.      *r = savechar;
  6837.      iap++;
  6838.    }
  6839.  }
  6840.  
  6841.  if (gp->debug_mode) {
  6842.    for (iap = infoarray, i = entrycount; i > 0; iap++, i--) {
  6843.      fprintf(gp->debug_file,"GGMdir: type = %d\n",iap->type);
  6844.      fprintf(gp->debug_file,"GGMdir: port = %d\n",iap->port);
  6845.      fprintf(gp->debug_file,"GGMdir: path = %s\n",iap->path);
  6846.      fprintf(gp->debug_file,"GGMdir: host = %s\n",iap->host);
  6847.      fprintf(gp->debug_file,"GGMdir: desc = %s\n",iap->desc);
  6848.      fprintf(gp->debug_file,"GGMdir: bmds = %s\n",iap->bmds);
  6849.      fprintf(gp->debug_file,"\n");
  6850.    }
  6851.  }
  6852.  
  6853.  display_dynamic_area(gp,ip,infoarray,entrycount);
  6854.  
  6855.  FREEMAIN(infoarray,"gopherinfo array");
  6856.  
  6857.  return TRUE;
  6858. }
  6859.  
  6860. ./ ADD NAME=GGMDISC
  6861.  
  6862.  /********************************************************************/
  6863.  /*                                                                  */
  6864.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  6865.  /*                                                                  */
  6866.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6867.  /*                                                                  */
  6868.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6869.  /* including the implied warranties of merchantability and fitness, */
  6870.  /* are expressly denied.                                            */
  6871.  /*                                                                  */
  6872.  /* Provided this copyright notice is included, this software may    */
  6873.  /* be freely distributed and not offered for sale.                  */
  6874.  /*                                                                  */
  6875.  /* Changes or modifications may be made and used only by the maker  */
  6876.  /* of same, and not further distributed.  Such modifications should */
  6877.  /* be mailed to the author for consideration for addition to the    */
  6878.  /* software and incorporation in subsequent releases.               */
  6879.  /*                                                                  */
  6880.  /********************************************************************/
  6881.  
  6882. #pragma  csect(code,  "GG@DISC ")
  6883. #pragma  csect(static,"GG$DISC ")
  6884. #include "gg.h"
  6885.  
  6886. /****** Disconnect from gopher server. ********************************/
  6887.  
  6888. void
  6889. GGMdisc(gp,sp)
  6890. Rstruc ggcb        *gp;
  6891. Rstruc connection  *sp;
  6892. {
  6893.  int                closerc;
  6894.  struct recvstruct *R;
  6895.  
  6896.  /* If local mode, close temporary file and return. */
  6897.  
  6898.  if ((R=gp->recvp)) {
  6899.    if (R->outfp) {
  6900.      if (fclose(R->outfp) < 0) {
  6901.        CRIT1("Error closing local mode temporary file");
  6902.      }
  6903.      R->outfp = NULL;
  6904.    }
  6905.  
  6906.    sp->connected_to_server   = FALSE;
  6907.  
  6908.    FREEMAIN(gp->recvp,"local mode recv struct");
  6909.    gp->recvp = NULL;
  6910.    return;
  6911.  }
  6912.  
  6913.  sp->closing_connection    = TRUE;
  6914.  
  6915.  if (sp->connection_broken) {
  6916.    if (gp->debug_file) {
  6917.      fprintf(gp->debug_file,
  6918.   "Client %s (%s) connection with gopher server on %s (%s) was lost\n",
  6919.           gp->client_hostname,
  6920.           gp->client_ip_addrstr,
  6921.           gp->server_hostname,
  6922.           gp->server_ip_addrstr);
  6923.    }
  6924.    sp->connected_to_server   = FALSE;
  6925.  }
  6926.  else {
  6927.  
  6928.    /* In case of some kind of protocol error, don't let things hang. */
  6929.  
  6930.    GGMesrvr(gp,sp);         /* End server read */
  6931.  
  6932.    if (gp->debug_file) {
  6933.      fprintf(gp->debug_file,
  6934.       "Client %s (%s) disconnecting from gopher server on %s (%s)\n",
  6935.           gp->client_hostname,
  6936.           gp->client_ip_addrstr,
  6937.           gp->server_hostname,
  6938.           gp->server_ip_addrstr);
  6939.    }
  6940.  
  6941.    (void)GGMivput(gp,"GGSOLDER ",gp->server_hostname,-1);
  6942.    (void)GGMivput(gp,"GGSOLDIP ",gp->server_ip_addrstr,-1);
  6943.    (void)GGMispf(gp,"CONTROL DISPLAY LOCK");
  6944.    (void)GGMispf(gp,"DISPLAY PANEL(GGMLDISC)");
  6945.  
  6946.    /* In case of some kind of protocol error, don't let things hang. */
  6947.  
  6948.    GGMesrvr(gp,sp);                   /* End server read */
  6949.  
  6950.    sp->connected_to_server   = FALSE;
  6951.  
  6952.    TCP_DEBUG_ON;
  6953.    closerc = close(sp->ns);
  6954.    TCP_DEBUG_OFF;
  6955.  
  6956.    if (closerc < 0) {
  6957.      ERR2("TCP/IP error: close() failed to disconnect from server %s.",
  6958.           gp->ggserver);
  6959.    }
  6960.  }
  6961.  
  6962.  return;
  6963. }
  6964.  
  6965. ./ ADD NAME=GGMDISPL
  6966.  
  6967.  /********************************************************************/
  6968.  /*                                                                  */
  6969.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  6970.  /*                                                                  */
  6971.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  6972.  /*                                                                  */
  6973.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  6974.  /* including the implied warranties of merchantability and fitness, */
  6975.  /* are expressly denied.                                            */
  6976.  /*                                                                  */
  6977.  /* Provided this copyright notice is included, this software may    */
  6978.  /* be freely distributed and not offered for sale.                  */
  6979.  /*                                                                  */
  6980.  /* Changes or modifications may be made and used only by the maker  */
  6981.  /* of same, and not further distributed.  Such modifications should */
  6982.  /* be mailed to the author for consideration for addition to the    */
  6983.  /* software and incorporation in subsequent releases.               */
  6984.  /*                                                                  */
  6985.  /********************************************************************/
  6986.  
  6987.  /********************************************************************/
  6988.  
  6989. #pragma  csect(code,  "GG@DISPL")
  6990. #pragma  csect(static,"GG$DISPL")
  6991. #include "gg.h"
  6992.  
  6993. #ifdef FETCH
  6994. #define VL_BIT(X) ((unsigned int)(X) | 0x80000000)
  6995. #else
  6996. #define VL_BIT(X) (X)
  6997. #endif
  6998.  
  6999. /****** Display ISPF panel. ******************************************/
  7000.  
  7001. int
  7002. GGMdispl(gp,pan8)
  7003. Rstruc ggcb    *gp;
  7004. char           *pan8;
  7005. {
  7006.  
  7007.  if (gp->setmsg) {
  7008.    gp->ispfrc = ISPLINK("DISPLAY ", pan8, VL_BIT("ISRZ002 "));
  7009.  }
  7010.  else {
  7011.    gp->ispfrc = ISPLINK("DISPLAY ", VL_BIT(pan8));
  7012.  }
  7013.  
  7014.  if (gp->ispfrc > 8) GGMierr(gp);   /* display ISPF error */
  7015.  
  7016.  gp->setmsg = FALSE;
  7017.  
  7018.  return gp->ispfrc;
  7019. }
  7020.  
  7021. ./ ADD NAME=GGMDSOPT
  7022.  
  7023.  /********************************************************************/
  7024.  /*                                                                  */
  7025.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  7026.  /*                                                                  */
  7027.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7028.  /*                                                                  */
  7029.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7030.  /* including the implied warranties of merchantability and fitness, */
  7031.  /* are expressly denied.                                            */
  7032.  /*                                                                  */
  7033.  /* Provided this copyright notice is included, this software may    */
  7034.  /* be freely distributed and not offered for sale.                  */
  7035.  /*                                                                  */
  7036.  /* Changes or modifications may be made and used only by the maker  */
  7037.  /* of same, and not further distributed.  Such modifications should */
  7038.  /* be mailed to the author for consideration for addition to the    */
  7039.  /* software and incorporation in subsequent releases.               */
  7040.  /*                                                                  */
  7041.  /********************************************************************/
  7042.  
  7043. #pragma  csect(code,  "GG@DSOPT")
  7044. #pragma  csect(static,"GG$DSOPT")
  7045. #include "gg.h"
  7046.  
  7047. /****** Set options. *************************************************/
  7048.  
  7049. static void
  7050. set_options(gp,panelname,which)
  7051. Rstruc ggcb       *gp;
  7052. char              *panelname;
  7053. enum user_option   which;
  7054. {
  7055.  
  7056.  while (GGMdispl(gp,panelname) == 0) {
  7057.    GGMsopt(gp,which);               /* Actually set options */
  7058.  }
  7059.  
  7060.  return;
  7061. }
  7062.  
  7063. /****** Option ... set GOPHER default processing options. ***********/
  7064.  
  7065. void
  7066. GGMdsopt(gp,option)
  7067. Rstruc ggcb *gp;
  7068. char        *option;
  7069. {
  7070.  Bool        asked_for;
  7071.  Bool        force_choice;
  7072.  char        ggchoice[9];
  7073.  
  7074.  force_choice = FALSE;
  7075.  
  7076.  do {
  7077.  
  7078.    asked_for = TRUE;
  7079.  
  7080.    if (!force_choice && option && *option) {
  7081.      strncpy(ggchoice,option,sizeof(ggchoice)-1);
  7082.  
  7083.    }
  7084.    else {
  7085.  
  7086.      (void)GGMispf(gp,"ADDPOP");
  7087.      if (GGMdispl(gp,"GGMPOPT ") > 0) {
  7088.        asked_for = FALSE;
  7089.      }
  7090.      else {
  7091.        (void)GGMivget(gp,"GGCHOICE ",ggchoice,sizeof(ggchoice));
  7092.        if (*ggchoice == '?') {
  7093.          ERR1("Invalid choice;\
  7094. Move the cursor to a selection (or type S next to it) and press ENTER."
  7095.              );
  7096.        }
  7097.      }
  7098.  
  7099.      (void)GGMispf(gp,"REMPOP");
  7100.    }
  7101.  
  7102.    if (asked_for) {
  7103.  
  7104.      if      (EQUAL(ggchoice,"1")) {
  7105.        set_options(gp,"GGMOPT1 ",OPTION_VIEW);
  7106.        break;
  7107.      }
  7108.      else if (EQUAL(ggchoice,"2")) {
  7109.        set_options(gp,"GGMOPT2 ",OPTION_OTHER);
  7110.        break;
  7111.      }
  7112.      else {
  7113.        ERR1("Invalid choice;\
  7114. Move the cursor to a selection (or type S next to it) and press ENTER."
  7115.            );
  7116.        force_choice = TRUE;
  7117.        continue;
  7118.      }
  7119.    }
  7120.  
  7121.  } while (asked_for);
  7122.  
  7123.  return;
  7124.  
  7125. }
  7126.  
  7127. ./ ADD NAME=GGMDUMP
  7128.  
  7129.  /********************************************************************/
  7130.  /*                                                                  */
  7131.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  7132.  /*                                                                  */
  7133.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7134.  /*                                                                  */
  7135.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7136.  /* including the implied warranties of merchantability and fitness, */
  7137.  /* are expressly denied.                                            */
  7138.  /*                                                                  */
  7139.  /* Provided this copyright notice is included, this software may    */
  7140.  /* be freely distributed and not offered for sale.                  */
  7141.  /*                                                                  */
  7142.  /* Changes or modifications may be made and used only by the maker  */
  7143.  /* of same, and not further distributed.  Such modifications should */
  7144.  /* be mailed to the author for consideration for addition to the    */
  7145.  /* software and incorporation in subsequent releases.               */
  7146.  /*                                                                  */
  7147.  /********************************************************************/
  7148.  
  7149. #pragma  csect(code,  "GG@DUMP ")
  7150. #pragma  csect(static,"GG$DUMP ")
  7151. #include "gg.h"
  7152.  
  7153. /****** Dump some data. **********************************************/
  7154.  
  7155. void
  7156. GGMdump(struct ggcb *gp, char *label, char *p,int r)
  7157. {
  7158.  int i;
  7159.  
  7160.  if (!gp->debug_file) return;
  7161.  
  7162.  if (r == -2) {
  7163.    fprintf(gp->debug_file,"%s:  %d\n",label,(int)p);
  7164.    return;
  7165.  }
  7166.  
  7167.  if (r == -1) r = strlen(p);
  7168.  
  7169.  fprintf(gp->debug_file,"%s:   (%d characters)\n",label,r);
  7170.  for (i=0;i<77;i++) fprintf(gp->debug_file,"-");
  7171.  fprintf(gp->debug_file,"\n");
  7172.  for (i=0;i<r;i++) {
  7173.    char c = *(p+i);
  7174.    if (isprint(c))  fprintf(gp->debug_file,"%c",c);
  7175.    else             fprintf(gp->debug_file,"<0x%2.2x>",c);
  7176.  }
  7177.  fprintf(gp->debug_file,"\n");
  7178.  for (i=0;i<77;i++) fprintf(gp->debug_file,"-");
  7179.  fprintf(gp->debug_file,"\n");
  7180.  
  7181.  return;
  7182.  
  7183. }
  7184.  
  7185. ./ ADD NAME=GGMESRVR
  7186.  
  7187.  /********************************************************************/
  7188.  /*                                                                  */
  7189.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  7190.  /*                                                                  */
  7191.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7192.  /*                                                                  */
  7193.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7194.  /* including the implied warranties of merchantability and fitness, */
  7195.  /* are expressly denied.                                            */
  7196.  /*                                                                  */
  7197.  /* Provided this copyright notice is included, this software may    */
  7198.  /* be freely distributed and not offered for sale.                  */
  7199.  /*                                                                  */
  7200.  /* Changes or modifications may be made and used only by the maker  */
  7201.  /* of same, and not further distributed.  Such modifications should */
  7202.  /* be mailed to the author for consideration for addition to the    */
  7203.  /* software and incorporation in subsequent releases.               */
  7204.  /*                                                                  */
  7205.  /********************************************************************/
  7206.  
  7207. #pragma  csect(code,  "GG@ESRVR")
  7208. #pragma  csect(static,"GG$ESRVR")
  7209. #include "gg.h"
  7210.  
  7211. /****** End server read. *********************************************/
  7212.  
  7213. void
  7214. GGMesrvr(gp,sp)
  7215. Rstruc ggcb       *gp;
  7216. Rstruc connection *sp;
  7217. {
  7218.  char             *lp;
  7219.  Bool              found_more_server_data = FALSE;
  7220.  
  7221.  if (!gp)        return;
  7222.  if (sp->is_ftp) return;               /* not relevant to FTP sockets */
  7223.  
  7224.  GGMclrtx(gp,NULL);                    /* Clear text */
  7225.  
  7226.  if (gp->recvp) return;                /* Skip if non-socket */
  7227.  
  7228.  do {
  7229.  
  7230.    if (GGMgsrvl(gp,sp,&lp,FALSE)) {    /* Get server line */
  7231.      if (lp) {
  7232.        found_more_server_data = TRUE;
  7233.        (void)GGMouttx(gp,lp,NULL);     /* Output text line */
  7234.      }
  7235.    }
  7236.  
  7237.  } while (lp);
  7238.  
  7239.  if (found_more_server_data) {
  7240.    ERR1(
  7241. "More data was returned by the GOPHER server than GOPHER expected."
  7242.        );
  7243.    GGMvtx(gp,NULL,TRUE);              /* View text */
  7244.  }
  7245.  
  7246.  return;
  7247. }
  7248.  
  7249. ./ ADD NAME=GGMFREEM
  7250.  
  7251.  /********************************************************************/
  7252.  /*                                                                  */
  7253.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  7254.  /*                                                                  */
  7255.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7256.  /*                                                                  */
  7257.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7258.  /* including the implied warranties of merchantability and fitness, */
  7259.  /* are expressly denied.                                            */
  7260.  /*                                                                  */
  7261.  /* Provided this copyright notice is included, this software may    */
  7262.  /* be freely distributed and not offered for sale.                  */
  7263.  /*                                                                  */
  7264.  /* Changes or modifications may be made and used only by the maker  */
  7265.  /* of same, and not further distributed.  Such modifications should */
  7266.  /* be mailed to the author for consideration for addition to the    */
  7267.  /* software and incorporation in subsequent releases.               */
  7268.  /*                                                                  */
  7269.  /********************************************************************/
  7270.  
  7271. #pragma  csect(code,  "GG@FREEM")
  7272. #pragma  csect(static,"GG$FREEM")
  7273. #include "gg.h"
  7274.  
  7275. /****** Free memory. *************************************************/
  7276.  
  7277. void
  7278. GGMfreem(gp,stuff,whatfor)
  7279. Rstruc ggcb    *gp;
  7280. char           *stuff;
  7281. char           *whatfor;
  7282. {
  7283.  
  7284.  free(stuff);
  7285.  
  7286.  if (gp->debug_file) {
  7287.    fprintf(gp->debug_file,"GGMfreem: freed memory for %s\n", whatfor);
  7288.  }
  7289.  return;
  7290.  
  7291. }
  7292.  
  7293. ./ ADD NAME=GGMFTP
  7294.  
  7295.  /********************************************************************/
  7296.  /*                                                                  */
  7297.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7298.  /*                                                                  */
  7299.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7300.  /* including the implied warranties of merchantability and fitness, */
  7301.  /* are expressly denied.                                            */
  7302.  /*                                                                  */
  7303.  /* Provided this copyright notice is included, this software may    */
  7304.  /* be freely distributed and not offered for sale.                  */
  7305.  /*                                                                  */
  7306.  /* Changes or modifications may be made and used only by the maker  */
  7307.  /* of same, and not further distributed.  Such modifications should */
  7308.  /* be mailed to the author for consideration for addition to the    */
  7309.  /* software and incorporation in subsequent releases.               */
  7310.  /*                                                                  */
  7311.  /********************************************************************/
  7312.  
  7313. #pragma  csect(code,  "GG@MFTP")
  7314. #pragma  csect(static,"GG$MFTP")
  7315.  
  7316. #include "gg.h"
  7317.  
  7318.  /* Logic: use basic FTP protocol to get a directory or a file and
  7319.   *        write the results to the passed file pointer.
  7320.   *        Note: does not use PASV (win).
  7321.   */
  7322.  
  7323. #define  IPPORT_FTPD    20                /* FTP data port */
  7324. #define  IPPORT_FTP     21                /* FTP control port */
  7325. #define  SHOW(A)        fprintf(stderr,"%s\n",(A))
  7326. #define  BLATHER        if (F->verboseflag) fprintf
  7327. #define  FLOSE          cleanup(F); return(FALSE)
  7328. #define  FSEND(A,B)     if (!fsend(F,CS,(A),(B))) {FLOSE;}
  7329. #define  FRECV()        if (!frecv(F,CS,TRUE))    {FLOSE;}
  7330. #define  FEXPECT(A)     if (!fexpect(F,A))        {FLOSE;}
  7331.  
  7332. /* ---- Format an Internet address. -------------------------------- */
  7333.  
  7334. static void
  7335. ip_address(IPADDRESS    n,
  7336.            char        *c
  7337.           )
  7338. {
  7339.  char                  *cp = (char *)&n;
  7340.  
  7341.  sprintf(c,"%d.%d.%d.%d", (unsigned char)*cp,
  7342.                           (unsigned char)*(cp+1),
  7343.                           (unsigned char)*(cp+2),
  7344.                           (unsigned char)*(cp+3));
  7345.  return;
  7346. }
  7347.  
  7348. /* ---- Format an FTP port address. -------------------------------- */
  7349.  
  7350. static void
  7351. port_address(
  7352.              struct Ftp  *F,         /* needed by BLATHER macro */
  7353.              IPADDRESS    addrnum,
  7354.              int          portnum,
  7355.              char        *c
  7356.             )
  7357. {
  7358.  char                    *ap = (char *)&addrnum;
  7359.  char                    *pp = (char *)&portnum;
  7360.  
  7361.  BLATHER(stderr,"port_address: addrnum=%8.8X, portnum=%8.8X\n",
  7362.                 addrnum,portnum);
  7363.  
  7364.  sprintf(c,"%d,%d,%d,%d,%d,%d", (unsigned char)*(ap+0),
  7365.                                 (unsigned char)*(ap+1),
  7366.                                 (unsigned char)*(ap+2),
  7367.                                 (unsigned char)*(ap+3),
  7368.                                 (unsigned char)*(pp+2),
  7369.                                 (unsigned char)*(pp+3));
  7370.  
  7371.  return;
  7372. }
  7373.  
  7374. /* ---- Close socket. ---------------------------------------------- */
  7375.  
  7376. static Bool
  7377. ftp_close(
  7378.           struct Ftp  *F,
  7379.           SOCKETNO     s
  7380.          )
  7381. {
  7382.  
  7383.  BLATHER(stderr,"Closing socket %d\n",s);
  7384.  
  7385.  if (close(s) < 0) {
  7386.    REPORT_TCP_ERROR("close");
  7387.    return FALSE;
  7388.  }
  7389.  
  7390.  return TRUE;
  7391.  
  7392. }
  7393.  
  7394. /* ---- Connect to the FTP server host. ---------------------------- */
  7395.  
  7396. static SOCKETNO
  7397. ftp_connect(
  7398.             struct Ftp  *F,
  7399.             char        *ftphost
  7400.            )
  7401. {
  7402.  SOCKETNO                ftpsock;
  7403.  int                     bindrc;
  7404.  int                     listrc;
  7405.  int                     connrc;
  7406.  char                    ipstring[65];
  7407.  
  7408.  ftpsock = -1;
  7409.  gethostname(F->client_hostname,sizeof(F->client_hostname));
  7410.  F->client_hostent = gethostbyname(F->client_hostname);
  7411.  if (!F->client_hostent) {
  7412.    REPORT_TCP_ERROR("gethostbyname for client hostname");
  7413.    return -1;
  7414.  }
  7415.  F->hostaddress = *(IPADDRESS *)F->client_hostent->h_addr_list[0];
  7416.  
  7417.  ip_address(F->hostaddress,ipstring);
  7418.  BLATHER(stderr,"client %s [%s]\n",F->client_hostname,ipstring);
  7419.  
  7420.  ftpsock = socket(AF_INET, SOCK_STREAM, 0);
  7421.  if (ftpsock < 0) {
  7422.    REPORT_TCP_ERROR("socket");
  7423.    return -1;
  7424.  }
  7425.  
  7426.  F->bindsock.sin_family      = AF_INET;
  7427.  F->bindsock.sin_port        = 0;
  7428.  F->bindsock.sin_addr.s_addr = F->hostaddress;
  7429.  
  7430.  bindrc = Bind(ftpsock,&F->bindsock,sizeof(F->bindsock));
  7431.  if (bindrc < 0) {
  7432.    REPORT_TCP_ERROR("bind for client");
  7433.    return -1;
  7434.  }
  7435.  
  7436.  F->server_hostent = gethostbyname(ftphost);
  7437.  if (!F->server_hostent) {
  7438.    fprintf(F->errfp,"gethostbyname: unknown host %s\n",ftphost);
  7439.    return -1;
  7440.  }
  7441.  F->hostaddress = *(IPADDRESS *)F->server_hostent->h_addr;
  7442.  strcpy(F->server_hostname,ftphost);
  7443.  ip_address(F->hostaddress,ipstring);
  7444.  BLATHER(stderr,"server %s [%s]\n",F->server_hostname,ipstring);
  7445.  
  7446.  F->consock.sin_family      = AF_INET;
  7447.  F->consock.sin_port        = htons(IPPORT_FTP);
  7448.  F->consock.sin_addr.s_addr = F->hostaddress;
  7449.  
  7450.  connrc = Connect(ftpsock,&F->consock,sizeof(F->consock));
  7451.  if (connrc < 0) {
  7452.    REPORT_TCP_ERROR(ftphost);
  7453.    return -1;
  7454.  }
  7455.  
  7456.  return ftpsock;
  7457. }
  7458.  
  7459. /* --- Get a response from the FTP server. ------------------ */
  7460.  
  7461. static Bool
  7462. frecv(F,S,doread)
  7463. struct Ftp        *F;
  7464. struct connection *S;
  7465. Bool               doread;
  7466. {
  7467.  
  7468.  S->dont_read = !doread;
  7469.  if (!GGMgsrvl(NULL,S,NULL,FALSE)) return FALSE;
  7470.  if (S->time_to_go_home) return FALSE;
  7471.  if (!S->server_has_something_pending) return TRUE;
  7472.  if (F->verboseflag) SHOW(S->server_buf);
  7473.  return TRUE;
  7474.  
  7475. }
  7476.  
  7477. /* --- Send a request to the FTP server. ----------------------- */
  7478.  
  7479. static Bool
  7480. fsend(F,S,text,arg)
  7481. struct Ftp        *F;
  7482. struct connection *S;
  7483. char              *text;
  7484. char              *arg;
  7485. {
  7486.  
  7487.  /* first check if there is anything pending from the server */
  7488.  
  7489.  (void)frecv(F,S,FALSE);
  7490.  
  7491.  /* now send */
  7492.  
  7493.  sprintf(S->client_buf,text,arg);
  7494.  
  7495.  if (F->verboseflag) SHOW(S->client_buf);
  7496.  
  7497.  return GGMsockt(NULL,S);
  7498. }
  7499.  
  7500. /* --- Retrieve a response and insure it was the expected one. -- */
  7501.  
  7502. static Bool
  7503. fexpect(F,mesid)
  7504. struct Ftp         *F;
  7505. char               *mesid;
  7506. {
  7507.  struct connection *S = &F->control_connection;
  7508.  
  7509.  for (;;) {
  7510.    if (!frecv(F,S,TRUE)) return FALSE;
  7511.    if (S->server_buf[0] == '\0') continue;
  7512.    if (S->server_buf[0] == ' ')  continue;
  7513.    if (strlen(S->server_buf) > 3) {
  7514.      if (!memcmp(mesid,S->server_buf,3)) {
  7515.        if (S->server_buf[3] == '-')  continue;
  7516.        if (S->server_buf[3] == '\0') break;
  7517.        if (S->server_buf[3] == ' ')  break;
  7518.      }
  7519.    }
  7520.    fprintf(F->errfp,"Unexpected FTP response from %s:\n%s\n",
  7521.                     F->server_hostname, S->server_buf);
  7522.    return FALSE;
  7523.  }
  7524.  
  7525.  return TRUE;
  7526. }
  7527.  
  7528. /*================================================================*/
  7529.  
  7530. static Bool
  7531. ls_to_gopher(struct Ftp *F,
  7532.              char       *buf,
  7533.              int        *lenp
  7534.             )
  7535.  
  7536. {
  7537. #define     NUMBER_OF_WORDS  12
  7538.  char      *word[NUMBER_OF_WORDS];
  7539.  char      *cp;
  7540.  char      *ep;
  7541.  char      *mode;
  7542.  char      *name;
  7543.  char      *arrow;
  7544.  char      *symlink;
  7545.  int        i;
  7546.  int        maxwords;
  7547.  char       outtype;
  7548.  char       vmname  [ 33];
  7549.  char       rfile   [513];
  7550.  char       outname [513];
  7551.  char       outpath [513];
  7552.  
  7553.  /*
  7554.  BLATHER(stderr,"Calling ls_to_gopher on %*.*s\n",*lenp,*lenp,buf);
  7555.  */
  7556.  
  7557.  for (i = 0; i < NUMBER_OF_WORDS; i++) word[i] = "";
  7558.  
  7559.  /* Loop setting word[...] pointers to words in the buffer. */
  7560.  
  7561.  buf[*lenp] = '\0';
  7562.  
  7563.  for (i = 0, cp = skip_whitespace(buf);
  7564.       i < NUMBER_OF_WORDS;
  7565.       cp = skip_whitespace(ep)) {
  7566.    word[i++] = cp;
  7567.    if ((ep=strchr(cp,' '))) *ep++ = '\0';
  7568.    else break;
  7569.  }
  7570.  
  7571.  maxwords = i;
  7572.  
  7573.  /*
  7574.   * Normal Unix-style ls output:
  7575.   *
  7576.   * 0     1     2     3     4     5     6    7
  7577.   * mode  block user  size  month day   time name
  7578.   *
  7579.   * or
  7580.   *
  7581.   * 0     1     2     3     4     5     6    7     8
  7582.   * mode  block user  group size  month day  time  name
  7583.   *
  7584.   * or
  7585.   *
  7586.   * 0     1     2     3     4     5     6    7     8     9    10
  7587.   * mode  block user  group size  month day  time  name  -->  real
  7588.   *
  7589.   *
  7590.   * VM/CMS server output:
  7591.   *
  7592.   * 0     1     2     3     4     5     6    7     8
  7593.   * fname fmode ftype stuff stuff stuff date time  disk?
  7594.   *
  7595.   */
  7596.  
  7597.  if (maxwords < 8) return FALSE;
  7598.  else if (F->os == VM_OS) {
  7599.    sprintf(vmname,"%s.%s",word[0],word[1]);
  7600.    mode    = "-r--r--r--";
  7601.    name    = vmname;
  7602.    arrow   = "";
  7603.    symlink = "";
  7604.  }
  7605.  else if (maxwords == 8) {
  7606.    mode    = word[0];
  7607.    name    = word[7];
  7608.    arrow   = "";
  7609.    symlink = "";
  7610.  }
  7611.  else {
  7612.    mode    = word[0];
  7613.    name    = word[8];
  7614.    arrow   = word[9];
  7615.    symlink = word[10];
  7616.  }
  7617.  
  7618.  if (!*name) return FALSE;
  7619.  
  7620.  if (EQUAL(arrow,"->")) {
  7621.    if (symlink[0] == '/')  strcpy(rfile,symlink);
  7622.    else                    sprintf(rfile,"%s/%s",F->path,symlink);
  7623.  }
  7624.  else {
  7625.    if (name[0] == '/')     strcpy(rfile,name);
  7626.    else                    sprintf(rfile,"%s/%s",F->path,name);
  7627.  }
  7628.  sprintf(outname,"%s: %s:     %s %s %s",
  7629.                  F->host, F->path, name, arrow, symlink);
  7630.  switch (mode[0]) {
  7631.    case '-': outtype = '0'; break;
  7632.    case 'd':
  7633.    case 'D': outtype = '1'; break;
  7634.    case 'l':
  7635.    case 'L': outtype = '1'; break;
  7636.    default:  BLATHER(stderr,"Unknown mode %s\n",mode); return FALSE;
  7637.  }
  7638.  
  7639.  if (outtype == '1' || *symlink) {
  7640.    /* strcat(rfile,"/"); */
  7641.    outtype = '1';
  7642.  }
  7643.  
  7644.  sprintf(outpath,"%s%c:%s:%s:%s:%s",
  7645.                  F->ftphack, outtype, F->host, F->user, F->pass, rfile);
  7646.  
  7647.  sprintf(buf,"%c%s\t%s\t%s\t%d\n",
  7648.              outtype, outname, outpath, F->myname, F->myport);
  7649.  
  7650.  (*lenp) = strlen(buf);
  7651.  
  7652.  return TRUE;
  7653. }
  7654.  
  7655. /*================================================================*/
  7656.  
  7657. static int
  7658. emit(struct Ftp *F,
  7659.      char       *buf,
  7660.      int         len
  7661.     )
  7662. {
  7663.  int             fwriterc;
  7664.  Bool            got_a_record;
  7665.  char            newbuf[1024];
  7666.  
  7667.    memcpy(newbuf,buf,len);
  7668.  
  7669.    if (F->listflag) {
  7670.      got_a_record = ls_to_gopher(F,newbuf,&len);
  7671.    }
  7672.    else {
  7673.      newbuf[len++] = '\n';
  7674.      got_a_record = TRUE;
  7675.    }
  7676.    if (got_a_record) {
  7677.      fwriterc = fwrite(newbuf,1,len,F->outfp);
  7678.      if (fwriterc < len) {
  7679.        fprintf(stderr,"Error writing to FTP output file\n");
  7680.      }
  7681.    }
  7682.    else fwriterc = 0;
  7683.  
  7684.    return fwriterc;
  7685.  
  7686. }
  7687.  
  7688. /*================================================================*/
  7689.  
  7690. static Bool
  7691. viewable(char *fname)
  7692. {
  7693.  int           len;
  7694.  int           i;
  7695.  
  7696. #define REJECT_SUFFIX(A)     i = sizeof(A)-1; \
  7697.                              if (len > i && !memcmp(fname+len-i,A,i)) \
  7698.                                 return FALSE;
  7699.  
  7700.  len = strlen(fname);
  7701.  
  7702.  REJECT_SUFFIX(".Z"     );
  7703.  REJECT_SUFFIX(".PS"    );
  7704.  REJECT_SUFFIX(".ps"    );
  7705.  REJECT_SUFFIX(".tar"   );
  7706.  REJECT_SUFFIX(".zip"   );
  7707.  
  7708.  return TRUE;
  7709. }
  7710.  
  7711. /*================================================================*/
  7712.  
  7713. static void
  7714. cleanup(struct Ftp *F)
  7715. {
  7716.  struct connection *CS;
  7717.  struct connection *DS;
  7718.  
  7719.  CS = &F->control_connection;
  7720.  DS = &F->data_connection;
  7721.  
  7722.  if (F->listen_socket_opened) {
  7723.    (void)ftp_close(F,F->listensocket);
  7724.    F->listen_socket_opened = FALSE;
  7725.  }
  7726.  
  7727.  if (F->accept_socket_opened) {
  7728.    (void)ftp_close(F,DS->ns);
  7729.    F->accept_socket_opened = FALSE;
  7730.  }
  7731.  
  7732.  if (F->control_socket_opened) {
  7733.    (void)ftp_close(F,CS->ns);
  7734.    F->control_socket_opened = FALSE;
  7735.  }
  7736.  
  7737. }
  7738.  
  7739. /*================================================================*/
  7740.  
  7741. Bool
  7742. GGMftp(struct recvstruct *R,
  7743.        struct Ftp        *F
  7744.       )
  7745. {
  7746.  Bool                 rc = FALSE;
  7747.  char                *cp;
  7748.  char                *ftpgetf = NULL;
  7749.  char                *ftproot = NULL;
  7750.  int                  n;
  7751.  int                  i;
  7752.  int                  socksize;
  7753.  int                  accept_count;
  7754.  int                  bytes_to_write;
  7755.  int                  fwriterc;
  7756.  int                  bytes_written;
  7757.  struct connection   *CS;
  7758.  struct connection   *DS;
  7759.  struct sockaddr_in   datasocket;
  7760.  struct sockaddr_in   controlsocket;
  7761.  char                 port                  [81];
  7762.  char                 control_server_buffer [SERVER_BUF_MSGSIZE+4];
  7763.  char                 data_server_buffer    [SERVER_BUF_MSGSIZE+4];
  7764.  char                 control_client_buffer [CLIENT_BUF_MSGSIZE+4];
  7765.  char                 data_client_buffer    [CLIENT_BUF_MSGSIZE+4];
  7766.  
  7767.  memset(&datasocket,0,sizeof(struct sockaddr_in));
  7768.  memset(&controlsocket,0,sizeof(struct sockaddr_in));
  7769.  CS = &F->control_connection;
  7770.  DS = &F->data_connection;
  7771.  CS->buf_index  = -1;
  7772.  DS->buf_index  = -1;
  7773.  CS->is_ftp     = TRUE;
  7774.  DS->is_ftp     = TRUE;
  7775.  CS->server_buf = control_server_buffer;
  7776.  DS->server_buf = data_server_buffer;
  7777.  CS->client_buf = control_client_buffer;
  7778.  DS->client_buf = data_client_buffer;
  7779.  F->myname      = R->myname;
  7780.  F->myport      = R->myport;
  7781.  F->control_socket_opened = FALSE;
  7782.  F->listen_socket_opened  = FALSE;
  7783.  F->accept_socket_opened  = FALSE;
  7784.  
  7785.  switch (F->type) {
  7786.    case 1:   F->listflag = TRUE;  /* this is a directory request */
  7787.              break;
  7788.    default:  F->listflag = FALSE;
  7789.              break;
  7790.  }
  7791.  
  7792.  switch (F->os) {
  7793.    case VM_OS: cp = strchr(F->path,'/');
  7794.                if (cp) {
  7795.                 *cp = '\0';
  7796.                 ftproot = F->path;
  7797.                 ftpgetf = cp + 1;
  7798.                }
  7799.                else {
  7800.                 ftproot = F->path;
  7801.                 ftpgetf = "";
  7802.                }
  7803.                break;
  7804.    default:    ftproot = "";
  7805.                ftpgetf = F->path;
  7806.                break;
  7807.  }
  7808.  
  7809.  if (!F->listflag && !viewable(ftpgetf)) {
  7810.    fprintf(F->errfp,
  7811.         "This Gopher server cannot retrieve files of this type: %s\n",
  7812.                     ftpgetf);
  7813.    FLOSE;
  7814.  }
  7815.  
  7816.  CS->ns = ftp_connect(F,F->host);
  7817.  if (CS->ns < 0) {FLOSE;}
  7818.  F->control_socket_opened = TRUE;
  7819.  
  7820.  BLATHER(stderr,"Connected to %s (socket %d).\n", F->host, CS->ns);
  7821.  
  7822.  FEXPECT("220");  /* server ready */
  7823.  
  7824.  FSEND("USER %s",F->user);
  7825.  FEXPECT("331");  /* password required */
  7826.  
  7827.  FSEND("PASS %s",F->pass);
  7828.  FEXPECT("230");  /* user logged in */
  7829.  
  7830.  /* must issue RETR command but open data connection first */
  7831.  
  7832.  F->listensocket = socket(AF_INET, SOCK_STREAM, 0);
  7833.  if (F->listensocket < 0) {
  7834.    REPORT_TCP_ERROR("data socket");
  7835.    FLOSE;
  7836.  }
  7837.  F->listen_socket_opened = TRUE;
  7838.  
  7839.  listen(F->listensocket,1); /* accept only one connection */
  7840.  
  7841.  /* get port number of data connection */
  7842.  
  7843.  socksize = sizeof(struct sockaddr);
  7844.  Getsockname(F->listensocket,&datasocket,&socksize);
  7845.  socksize = sizeof(struct sockaddr);
  7846.  Getsockname(CS->ns,&controlsocket,&socksize);
  7847.  datasocket.sin_addr.s_addr = controlsocket.sin_addr.s_addr;
  7848.  
  7849.  port_address(F,datasocket.sin_addr.s_addr,datasocket.sin_port,port);
  7850.  
  7851.  FSEND("PORT %s", port);
  7852.  FEXPECT("200");  /* command successful */
  7853.  
  7854.  FSEND("TYPE %s","A");          /* ascii type */
  7855.  FEXPECT("200");  /* type set to ... */
  7856.  
  7857.  if (*ftproot) {
  7858.    FSEND("CWD %s", ftproot);
  7859.    FEXPECT("250");  /* current working dir set to ... */
  7860.  }
  7861.  
  7862.  if (F->listflag) {
  7863.    if (!*ftpgetf) {FSEND("LIST", NULL);}
  7864.    else           {FSEND("LIST %s", ftpgetf);}
  7865.  }
  7866.  else if (F->nlstflag) {
  7867.    if (!*ftpgetf) {FSEND("NLST", NULL);}
  7868.    else           {FSEND("NLST %s", ftpgetf);}
  7869.  }
  7870.  else {
  7871.    FSEND("RETR %s", ftpgetf);
  7872.  }
  7873.  if (F->os == VM_OS && (F->listflag || F->nlstflag)) {
  7874.    FEXPECT("125");  /* List started OK */
  7875.  }
  7876.  else {
  7877.    FEXPECT("150");  /* data connection for... */
  7878.  }
  7879.  
  7880.  accept_count = 0;
  7881.  DS->ns = Accept(F->listensocket,NULL,&accept_count);
  7882.  if (DS->ns < 0) {
  7883.    REPORT_TCP_ERROR("accept");
  7884.    FLOSE;
  7885.  }
  7886.  F->accept_socket_opened = TRUE;
  7887.  
  7888.  /* get data from data connection */
  7889.  
  7890.  bytes_to_write = 0;
  7891.  bytes_written = 0;
  7892.  for (;;) {
  7893.    DS->time_to_go_home = FALSE;
  7894.    DS->server_has_something_pending = TRUE;
  7895.    if (!GGMgsrvl(NULL,DS,NULL,FALSE)) {FLOSE;}
  7896.    if (DS->time_to_go_home) break;
  7897.    if (!DS->server_has_something_pending) break;
  7898.    bytes_to_write = strlen(DS->server_buf)-1;
  7899.    fwriterc = emit(F,DS->server_buf,bytes_to_write);
  7900.    bytes_written += fwriterc;
  7901.  }
  7902.  
  7903.  /* Close the data socket before waiting for the server to return
  7904.   * connection acknowledgement.  The VM server enforces this.
  7905.   */
  7906.  
  7907.  (void)ftp_close(F,DS->ns);
  7908.  F->accept_socket_opened = FALSE;
  7909.  
  7910.  if (F->os == VM_OS) {
  7911.    FEXPECT("250");  /* ... completed successfully */
  7912.  }
  7913.  else {
  7914.    FEXPECT("226");  /* transfer complete */
  7915.  }
  7916.  
  7917.  
  7918.  
  7919.  FSEND("QUIT",NULL);
  7920.  FEXPECT("221");  /* goodbye */
  7921.  
  7922.  cleanup(F);
  7923.  return TRUE;
  7924.  
  7925. }
  7926.  
  7927. ./ ADD NAME=GGMGETDS
  7928.  
  7929.  /********************************************************************/
  7930.  /*                                                                  */
  7931.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  7932.  /*                                                                  */
  7933.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  7934.  /*                                                                  */
  7935.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  7936.  /* including the implied warranties of merchantability and fitness, */
  7937.  /* are expressly denied.                                            */
  7938.  /*                                                                  */
  7939.  /* Provided this copyright notice is included, this software may    */
  7940.  /* be freely distributed and not offered for sale.                  */
  7941.  /*                                                                  */
  7942.  /* Changes or modifications may be made and used only by the maker  */
  7943.  /* of same, and not further distributed.  Such modifications should */
  7944.  /* be mailed to the author for consideration for addition to the    */
  7945.  /* software and incorporation in subsequent releases.               */
  7946.  /*                                                                  */
  7947.  /********************************************************************/
  7948.  
  7949. #pragma  csect(code,  "GG@GETDS")
  7950. #pragma  csect(static,"GG$GETDS")
  7951. #include "gg.h"
  7952.  
  7953. #define DUMMY_FILE_POINTER_FOR_PDS  (FILE *)(-1)
  7954.  
  7955. struct sysout    {
  7956.                   int        copies;
  7957.                   char       class [2];
  7958.                   char       dest  [9];
  7959.                   char       forms [5];
  7960.                   char       ucs   [5];
  7961.                  };
  7962.  
  7963. #define FULLSYSOUT
  7964.  
  7965. /****** Function to close sequential data set after extraction. ******/
  7966.  
  7967. static void
  7968. close_seq(gp,ep,xfp,final)
  7969. Rstruc ggcb         *gp;
  7970. Rstruc extraction   *ep;
  7971. FILE                *xfp;
  7972. Fool                 final;
  7973. {
  7974.  
  7975.  if (fclose(xfp) < 0) {
  7976.    /* perror(ep->dsname); */
  7977.    ERR2("An error occurred closing %s.", ep->dsname);
  7978.    gp->extract_close_error = TRUE;
  7979.  }
  7980.  
  7981. }
  7982.  
  7983. /****** Function to close partitioned data set after extraction. *****/
  7984.  
  7985. static void
  7986. close_pds(gp,ep,xfp,final)
  7987. Rstruc ggcb         *gp;
  7988. Rstruc extraction   *ep;
  7989. FILE                *xfp;
  7990. Fool                 final;
  7991. {
  7992.  
  7993.  if (final) {
  7994.    (void)GGMunalc(ep->ddname);     /* Unallocate the PDS */
  7995.  }
  7996.  else {
  7997.    if (fclose(xfp) < 0) {
  7998.      /* perror(ep->dsname); */
  7999.      ERR2("An error occurred closing %s.", ep->dsname);
  8000.      gp->extract_close_error = TRUE;
  8001.    }
  8002.  }
  8003.  
  8004. }
  8005.  
  8006. /****** Function to close SYSOUT print file after printing. **********/
  8007.  
  8008. static void
  8009. close_jes(gp,ep,xfp,final)
  8010. Rstruc ggcb         *gp;
  8011. Rstruc extraction   *ep;
  8012. FILE                *xfp;
  8013. Fool                 final;
  8014. {
  8015.  
  8016.  if (fclose(xfp) < 0) {
  8017.    /* perror(ep->dsname); */
  8018.    ERR2("An error occurred closing %s.", ep->dsname);
  8019.    gp->extract_close_error = TRUE;
  8020.  }
  8021.  if (final) {
  8022.    (void)GGMunalc(ep->ddname);     /* Unallocate the SYSOUT file */
  8023.  }
  8024.  
  8025. }
  8026.  
  8027. /****** Allocate SYSOUT file. ****************************************/
  8028.  
  8029. static Bool
  8030. allocate_sysout(ep,sp)
  8031. Rstruc extraction   *ep;
  8032. Rstruc sysout       *sp;
  8033. {
  8034.  int          i;
  8035.  int          rc;
  8036.  char        *cp;
  8037.  __S99parms   stuff99;   /* The manual has it wrong.  No "struct". */
  8038.  TEXTUNIT    *tu [ 7];
  8039.  TEXTUNIT     tu_sysout;
  8040.  TEXTUNIT     tu_copies;
  8041.  TEXTUNIT     tu_dest;
  8042.  TEXTUNIT     tu_forms;
  8043.  TEXTUNIT     tu_ucs;
  8044.  TEXTUNIT     tu_rtddn;
  8045.  
  8046.  memset((char *)&stuff99,0,sizeof(__S99parms));
  8047.  
  8048.  stuff99.__S99RBLN   = 20;
  8049.  stuff99.__S99VERB   = S99VRBAL;
  8050.  stuff99.__S99FLAG1  = S99NOCNV << 8;
  8051.  stuff99.__S99ERROR  = 0;
  8052.  stuff99.__S99INFO   = 0;
  8053.  stuff99.__S99TXTPP  = tu;
  8054.  stuff99.__S99FLAG2  = 0;
  8055.  
  8056.  i = 0;
  8057.  
  8058.  tu[i++] = &tu_sysout;
  8059.  
  8060.  tu_sysout.key        = DALSYSOU;
  8061.  tu_sysout.num        = 1;
  8062.  tu_sysout.ent.len    = 1;
  8063.  tu_sysout.ent.prm[0] = toupper(sp->class[0]);
  8064.  
  8065.  tu[i++] = &tu_copies;
  8066.  
  8067.  tu_copies.key        = DALCOPYS;
  8068.  tu_copies.num        = 1;
  8069.  tu_copies.ent.len    = 1;
  8070.  tu_copies.ent.prm[0] = (unsigned char)sp->copies;
  8071.  
  8072.  if (sp->dest[0] > ' ') {
  8073.  
  8074.   tu[i++] = &tu_dest;
  8075.  
  8076.   tu_dest.key          = DALSUSER;
  8077.   tu_dest.num          = 1;
  8078.   copy_uppercase_and_strip_trailing(tu_dest.ent.prm,sp->dest,cp);
  8079.   tu_dest.ent.len      = cp - tu_dest.ent.prm;
  8080.  
  8081.  }
  8082.  
  8083.  if (sp->forms[0] > ' ') {
  8084.  
  8085.   tu[i++] = &tu_forms;
  8086.  
  8087.   tu_forms.key         = DALSFMNO;
  8088.   tu_forms.num         = 1;
  8089.   copy_uppercase_and_strip_trailing(tu_forms.ent.prm,sp->forms,cp);
  8090.   tu_forms.ent.len     = cp - tu_forms.ent.prm;
  8091.  
  8092.  }
  8093.  
  8094.  if (sp->ucs[0] > ' ') {
  8095.  
  8096.   tu[i++] = &tu_ucs;
  8097.  
  8098.   tu_ucs.key           = DALUCS;
  8099.   tu_ucs.num           = 1;
  8100.   copy_uppercase_and_strip_trailing(tu_ucs.ent.prm,sp->ucs,cp);
  8101.   tu_ucs.ent.len       = cp - tu_ucs.ent.prm;
  8102.  
  8103.  }
  8104.  
  8105.  tu[i++] = &tu_rtddn;
  8106.  
  8107.  tu_rtddn.key         = DALRTDDN;
  8108.  tu_rtddn.num         = 1;
  8109.  tu_rtddn.ent.len     = 8;
  8110.  memset(tu_rtddn.ent.prm,' ',8);
  8111.  
  8112.  tu[i] = (void *)0x80000000;
  8113.  
  8114.  rc = svc99(&stuff99);
  8115.  
  8116.  if (rc == 0) {
  8117.    memcpy(ep->ddname,(char *)tu_rtddn.ent.prm,8);
  8118.    ep->ddname[8] = ' ';
  8119.    *(strchr(ep->ddname,' ')) = '\0';
  8120.    return TRUE;
  8121.  }
  8122.  else {
  8123.    GGMdfail(rc,&stuff99);
  8124.    return FALSE;
  8125.  }
  8126. }
  8127.  
  8128. /****** Prompt user for the name of a data set to extract into. ******/
  8129.  
  8130. FILE *
  8131. GGMgetds(gp,ep)
  8132. Rstruc ggcb         *gp;
  8133. Rstruc extraction   *ep;
  8134. {
  8135.  FILE               *xfp;
  8136.  char               *bufptr;
  8137.  Bool                asked_for;
  8138.  Bool                do_warn;
  8139.  Bool                is_not_gopher_menu;
  8140.  struct sysout       sys;
  8141.  char                ggexdsn[65];    /* data set name for extraction */
  8142.  char                ggbmdsn[65];    /* data set name for bookmark   */
  8143.  char                ggexapp [4];    /* YES or NO for append mode    */
  8144.  char                ggextab [4];    /* YES or NO for tab expansion  */
  8145.  char                ggexblk [4];    /* YES or NO for blank after sep*/
  8146.  char                ggexsep[81];    /* Separator line (optional)    */
  8147.  char                ggexpmp [9];    /* PDS member name prefix       */
  8148.  char                ggexscl [2];    /* Print SYSOUT class name      */
  8149.  char                ggexsco [4];    /* Print SYSOUT copies number   */
  8150.  char                ggexsde [9];    /* Print SYSOUT destination     */
  8151.  char                ggexsfo [5];    /* Print SYSOUT forms           */
  8152.  char                ggexsuc [5];    /* Print SYSOUT UCS             */
  8153.  char                ddname  [9];
  8154.  char                member  [9];
  8155.  char                pdspec [32];
  8156.  char                quoted_dsname [67];
  8157.  char                formatted_number [11];
  8158.  char                buffer [RBUFSIZE];
  8159.  
  8160.  
  8161.  /* Display panel asking for data set name into which to extract. */
  8162.  
  8163.  xfp = NULL;
  8164.  asked_for = TRUE;
  8165.  
  8166.  (void)GGMispf(gp,"ADDPOP");
  8167.  
  8168.  (void)GGMivput(gp,"GGALLPR ",
  8169. #ifdef FULLSYSOUT
  8170.                      "Y",
  8171. #else
  8172.                      "",
  8173. #endif
  8174.                      -1);
  8175.  
  8176.  while (xfp == NULL) {
  8177.  
  8178.    /* Keep asking for a dsname until one works or END pressed. */
  8179.  
  8180.    if (GGMdispl(gp,ep->panelname) > 0) {
  8181.      WARN1("Request cancelled, because you pressed END.");
  8182.      asked_for = FALSE;
  8183.      xfp = NULL;
  8184.      break;
  8185.    }
  8186.  
  8187.    switch (ep->ex) {
  8188.      case EXTRACT_IT:
  8189.           (void)GGMivget(gp,"GGEXDSN ",ggexdsn,sizeof(ggexdsn));
  8190.           (void)GGMivget(gp,"GGEXTAB ",ggextab,sizeof(ggextab));
  8191.           if (ep->mode == PDS) {
  8192.             (void)GGMivget(gp,"GGEXPMP ",ggexpmp,sizeof(ggexpmp));
  8193.           }
  8194.           else {
  8195.             (void)GGMivget(gp,"GGEXAPP ",ggexapp,sizeof(ggexapp));
  8196.             (void)GGMivget(gp,"GGEXBLK ",ggexblk,sizeof(ggexblk));
  8197.             (void)GGMivget(gp,"GGEXSEP ",ggexsep,sizeof(ggexsep));
  8198.           }
  8199.           break;
  8200.      case PRINT_IT:
  8201.           (void)GGMivget(gp,"GGEXSCL ",ggexscl,sizeof(ggexscl));
  8202.           (void)GGMivget(gp,"GGEXSCO ",ggexsco,sizeof(ggexsco));
  8203. #ifdef FULLSYSOUT
  8204.           (void)GGMivget(gp,"GGEXSDE ",ggexsde,sizeof(ggexsde));
  8205.           (void)GGMivget(gp,"GGEXSFO ",ggexsfo,sizeof(ggexsfo));
  8206.           (void)GGMivget(gp,"GGEXSUC ",ggexsuc,sizeof(ggexsuc));
  8207. #else
  8208.           *ggexsde = '\0';
  8209.           *ggexsfo = '\0';
  8210.           *ggexsuc = '\0';
  8211. #endif
  8212.           (void)GGMivget(gp,"GGEXBLK ",ggexblk,sizeof(ggexblk));
  8213.           (void)GGMivget(gp,"GGEXSEP ",ggexsep,sizeof(ggexsep));
  8214.           break;
  8215.      case BOOKMARK_IT:
  8216.           (void)GGMivget(gp,"GGBMDSN ",ggbmdsn,sizeof(ggbmdsn));
  8217.           break;
  8218.    }
  8219.  
  8220.    if (ep->mode == PDS) {
  8221.  
  8222.      ep->closer = close_pds;
  8223.      ep->appending = FALSE;
  8224.      ep->blanking  = FALSE;
  8225.      strcpy(ep->separator,"");
  8226.      strcpy(ep->ddname,"");
  8227.      strcpy(ep->member_prefix,ggexpmp);
  8228.  
  8229.      /* Note: panel forces fully-qualified name to pass to allocate */
  8230.  
  8231.      if (ggexdsn[0] != '\'') {
  8232.        strcpy(quoted_dsname,"'");
  8233.        strcat(quoted_dsname,ggexdsn);
  8234.        strcat(quoted_dsname,"'");
  8235.      }
  8236.      else strcpy(quoted_dsname,ggexdsn);
  8237.  
  8238.      /* Check if PDS already exists. */
  8239.  
  8240.      if (gp->warn_overwrite) {
  8241.        if (TEST_IF_FILE_EXISTS(xfp,quoted_dsname)) {
  8242.          CLEANUP_IF_FILE_EXISTS(xfp);
  8243.          xfp = NULL;
  8244.          if (GGMdispl(gp,"GGMPEXPW") > 0) {
  8245.            WARN1("Operation cancelled, because you pressed END.");
  8246.            break;
  8247.          }
  8248.        }
  8249.      }
  8250.  
  8251.      if (GGMalloc(ggexdsn,ep->ddname,PDS,ep->count) != PDS) {
  8252.        ERR2("Allocation failed for data set %s.", ggexdsn);
  8253.        xfp = NULL;
  8254.        continue;
  8255.      }
  8256.      strcpy(ep->dsname,    ggexdsn);
  8257.      ep->tab_expanding = (ggextab[0] == 'Y');
  8258.      do_warn = (ep->appending ? gp->warn_append : gp->warn_overwrite);
  8259.    }
  8260.    else if (ep->mode == JES) {
  8261.      ep->closer = close_jes;
  8262.      strcpy(ep->separator, ggexsep);
  8263.      sprintf(ep->dsname,"SYSOUT class %s",ggexscl);
  8264.      strcpy(sys.class, ggexscl);
  8265.      sys.copies = atoi(ggexsco);
  8266.      if (sys.copies < 1) sys.copies = 1;
  8267.      strcpy(sys.dest,  ggexsde);
  8268.      strcpy(sys.forms, ggexsfo);
  8269.      strcpy(sys.ucs,   ggexsuc);
  8270.      ep->appending     = FALSE;
  8271.      ep->blanking      = (ggexblk[0] == 'Y');
  8272.      ep->tab_expanding = TRUE;
  8273.      do_warn = FALSE;
  8274.    }
  8275.    else if (ep->ex == BOOKMARK_IT) {
  8276.      ep->closer = close_seq;
  8277.      strcpy(ep->separator, "");
  8278.      strcpy(ep->dsname,    ggbmdsn);
  8279.      strcpy(ggexdsn,       ggbmdsn);
  8280.      ep->appending       = TRUE;
  8281.      ep->blanking        = FALSE;
  8282.      ep->tab_expanding   = FALSE;
  8283.      do_warn = FALSE;
  8284.    }
  8285.    else {
  8286.      ep->closer = close_seq;
  8287.      strcpy(ep->separator, ggexsep);
  8288.      strcpy(ep->dsname,    ggexdsn);
  8289.      ep->appending      = (ggexapp[0] == 'Y');
  8290.      ep->blanking       = (ggexblk[0] == 'Y');
  8291.      ep->tab_expanding  = (ggextab[0] == 'Y');
  8292.      do_warn = (ep->appending ? gp->warn_append : gp->warn_overwrite);
  8293.    }
  8294.  
  8295.    /* check if the dataset already exists */
  8296.  
  8297.    if (ep->ex == BOOKMARK_IT) {
  8298.      is_not_gopher_menu = FALSE;
  8299.      if (TEST_IF_FILE_EXISTS(xfp,ggexdsn)) {
  8300.        /* check that it is a gopher menu */
  8301.        CLEANUP_IF_FILE_EXISTS(xfp);
  8302.        xfp = fopen(ggexdsn,"r");
  8303.        if (xfp) {
  8304.          *buffer = '\0';
  8305.          fgets(buffer,sizeof(buffer),xfp);
  8306.          if (*buffer) {
  8307.            if ((bufptr=strchr(buffer,'\n'))) *bufptr = '\0';
  8308.            uppercase_in_place(buffer);
  8309.            bufptr = skip_whitespace(buffer);
  8310.            if (!EQUAL(bufptr,MENUIDENT)) is_not_gopher_menu = TRUE;
  8311.          }
  8312.          (void)fclose(xfp);
  8313.          xfp = NULL;
  8314.        }
  8315.        if (is_not_gopher_menu) {
  8316.          WARN2("Not a gopher bookmark or menu file: %s",ep->dsname);
  8317.          break;
  8318.        }
  8319.        ep->appending = TRUE;
  8320.      }
  8321.      else {
  8322.        ep->appending = FALSE;
  8323.      }
  8324.    }
  8325.    else if (ep->mode != JES) {
  8326.      if (do_warn) {
  8327.        if (TEST_IF_FILE_EXISTS(xfp,ggexdsn)) {
  8328.          CLEANUP_IF_FILE_EXISTS(xfp);
  8329.          xfp = NULL;
  8330.          if (GGMdispl(gp,"GGMPEXOW") > 0) {
  8331.            WARN1("Operation cancelled, because you pressed END.");
  8332.            break;
  8333.          }
  8334.        }
  8335.      }
  8336.    }
  8337.  
  8338.    if (ep->mode == JES) {
  8339.      if (allocate_sysout(ep,&sys)) {
  8340.        sprintf(ggexdsn,"dd:%s",ep->ddname);
  8341.      }
  8342.      else *ggexdsn = '\0';
  8343.    }
  8344.  
  8345.    if (ep->mode == PDS) {
  8346.      xfp = DUMMY_FILE_POINTER_FOR_PDS;
  8347.      break;
  8348.    }
  8349.  
  8350.    if (*ggexdsn) {
  8351.  
  8352.      if (ep->mode == JES) {
  8353.        xfp = OPEN_SYSOUT_FILE(ggexdsn);
  8354.      }
  8355.      else {
  8356.        xfp = OPEN_TEXT_FILE_FOR_WRITE_OR_APPEND(ggexdsn,ep->appending);
  8357.      }
  8358.  
  8359.      if (!xfp) {
  8360. #ifdef SNSTCPIP
  8361.        fprintf(stderr,"Open failure: errno=%d\n",GET_ERRNO);
  8362. #else
  8363.        fprintf(stderr,"Open failure: errno=%d\n",errno);
  8364. #endif
  8365.        perror(ggexdsn);
  8366.        ERR2("Cannot open data set %s.", ep->dsname);
  8367.      }
  8368.    }
  8369.  }
  8370.  
  8371.  (void)GGMispf(gp,"REMPOP");
  8372.  
  8373.  return xfp;
  8374.  
  8375. }
  8376.  
  8377. ./ ADD NAME=GGMGETM
  8378.  
  8379.  /********************************************************************/
  8380.  /*                                                                  */
  8381.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8382.  /*                                                                  */
  8383.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8384.  /*                                                                  */
  8385.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8386.  /* including the implied warranties of merchantability and fitness, */
  8387.  /* are expressly denied.                                            */
  8388.  /*                                                                  */
  8389.  /* Provided this copyright notice is included, this software may    */
  8390.  /* be freely distributed and not offered for sale.                  */
  8391.  /*                                                                  */
  8392.  /* Changes or modifications may be made and used only by the maker  */
  8393.  /* of same, and not further distributed.  Such modifications should */
  8394.  /* be mailed to the author for consideration for addition to the    */
  8395.  /* software and incorporation in subsequent releases.               */
  8396.  /*                                                                  */
  8397.  /********************************************************************/
  8398.  
  8399. #pragma  csect(code,  "GG@GETM ")
  8400. #pragma  csect(static,"GG$GETM ")
  8401. #include "gg.h"
  8402.  
  8403. /****** Get memory. **************************************************/
  8404.  
  8405. void
  8406. GGMgetm(gp,pointer,howmuch,whatfor)
  8407. Rstruc ggcb    *gp;
  8408. char          **pointer;
  8409. int             howmuch;
  8410. char           *whatfor;
  8411. {
  8412.  
  8413.  *pointer = (char *)malloc(howmuch);
  8414.  
  8415.  if (*pointer == NULL) {
  8416.    fprintf(stderr,"GGMgetm: Cannot obtain %d bytes of memory for %s\n",
  8417.                   howmuch,whatfor);
  8418.  }
  8419.  else if (gp->debug_file) {
  8420.    fprintf(gp->debug_file,"GGMgetm: got %d bytes of memory for %s\n",
  8421.                            howmuch,whatfor);
  8422.  }
  8423.  return;
  8424.  
  8425. }
  8426.  
  8427. ./ ADD NAME=GGMGOFOR
  8428.  
  8429.  /********************************************************************/
  8430.  /*                                                                  */
  8431.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8432.  /*                                                                  */
  8433.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8434.  /*                                                                  */
  8435.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8436.  /* including the implied warranties of merchantability and fitness, */
  8437.  /* are expressly denied.                                            */
  8438.  /*                                                                  */
  8439.  /* Provided this copyright notice is included, this software may    */
  8440.  /* be freely distributed and not offered for sale.                  */
  8441.  /*                                                                  */
  8442.  /* Changes or modifications may be made and used only by the maker  */
  8443.  /* of same, and not further distributed.  Such modifications should */
  8444.  /* be mailed to the author for consideration for addition to the    */
  8445.  /* software and incorporation in subsequent releases.               */
  8446.  /*                                                                  */
  8447.  /********************************************************************/
  8448.  
  8449. #pragma  csect(code,  "GG@GOFOR")
  8450. #pragma  csect(static,"GG$GOFOR")
  8451. #include "gg.h"
  8452.  
  8453. /********************************************************************/
  8454.  
  8455. static Bool
  8456. connect_to_gopher_server(gp,sp,ip,is_cr_needed)
  8457. Rstruc connection  *sp;
  8458. Rstruc ggcb        *gp;
  8459. Rstruc gopherinfo  *ip;
  8460. Fool                is_cr_needed;
  8461. {
  8462.  char              *lp;
  8463.  Bool               got_some;
  8464.  
  8465.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  8466.  strcpy(gp->gopher_command,ip->path);   /* Specify command to issue */
  8467.  gp->ginfo = ip;
  8468.  sp->receiving_text = FALSE;
  8469.  
  8470.  if (!GGMconn(gp,sp)) return FALSE;   /* Connect to gopher server */
  8471.  
  8472.  GOPHERSEND(gp,sp);                   /* Send socket command */
  8473.  
  8474.  GGMclrtx(gp,ip);                  /* Clear text */
  8475.  
  8476.  sp->receiving_text = TRUE;
  8477.  
  8478.  got_some = FALSE;
  8479.  do {
  8480.    if (GGMgsrvl(gp,sp,&lp,is_cr_needed)) {  /* Get server line */
  8481.      if (lp) {
  8482.        got_some = TRUE;
  8483.        (void)GGMouttx(gp,lp,ip);          /* Output text line */
  8484.      }
  8485.    }
  8486.  } while (lp);                            /* until no more lines */
  8487.  
  8488.  if (!got_some) {
  8489.    WARN2("No data available from server %s.\n",gp->ggserver);
  8490.    return FALSE;
  8491.  }
  8492.  
  8493.  return TRUE;
  8494.  
  8495. }
  8496.  
  8497. /****** Gopher it. ***************************************************/
  8498.  
  8499. Bool
  8500. GGMgofor(gp,ip,how)
  8501. Rstruc ggcb        *gp;
  8502. Rstruc gopherinfo  *ip;
  8503. GOHOW               how;
  8504. {
  8505.  Rstruc connection *sp;
  8506.  Bool               con;
  8507.  Bool               cr;
  8508.  Bool               rc;
  8509.  Bool             (*fun)(struct ggcb *,struct gopherinfo *,GOHOW);
  8510.  char                    savebook[63];
  8511.  sp = &gp->gopher_connection;
  8512.  
  8513.    /* (1) send initial path string to initial host
  8514.     * (2) get back data from host
  8515.     * (3) if it is a gopher directory, then do:
  8516.     *      - display "table" of items
  8517.     *      - for each item selected, call GGMgofor recursively
  8518.     *     else browse the file data
  8519.     * (4) bye
  8520.     */
  8521.  
  8522.  if (gp->debug_mode) {
  8523.    fprintf(gp->debug_file,"GGMgofor: type = %c\n",ip->type);
  8524.    fprintf(gp->debug_file,"GGMgofor: port = %d\n",ip->port);
  8525.    fprintf(gp->debug_file,"GGMgofor: path = %s\n",ip->path);
  8526.    fprintf(gp->debug_file,"GGMgofor: host = %s\n",ip->host);
  8527.    fprintf(gp->debug_file,"GGMgofor: desc = %s\n",ip->desc);
  8528.    fprintf(gp->debug_file,"GGMgofor: bmds = %s\n",ip->bmds);
  8529.  }
  8530.  
  8531.  switch (ip->type) {
  8532.    case GOPHER_FILE:     fun = GGMvtx;   con = TRUE;  cr = TRUE; break;
  8533.    case GOPHER_DIRECTORY:fun = GGMdir;   con = TRUE;  cr = TRUE; break;
  8534.    case GOPHER_TELNET:   fun = GGMtnet;  con = FALSE; cr = TRUE; break;
  8535.    case GOPHER_TN3270:   fun = GGMtnet;  con = FALSE; cr = TRUE; break;
  8536.    case GOPHER_WAIS:     fun = GGMwais;  con = FALSE; cr = TRUE; break;
  8537.    case GOPHER_WHOIS:    fun = GGMwhois; con = FALSE; cr = TRUE; break;
  8538.    case GOPHER_CSO:      fun = GGMcso;   con = FALSE; cr = FALSE;break;
  8539.    default:
  8540.         ERR2("Sorry, access via %s not supported", GGMtype(ip->type));
  8541.         return FALSE;
  8542.  }
  8543.  
  8544.  if (con) {
  8545.    if (!connect_to_gopher_server(gp,sp,ip,cr)) return FALSE;
  8546.  }
  8547.  
  8548.  /* Insure no connection is active once we do the real thing. */
  8549.  
  8550.  if (sp->connected_to_server) {
  8551.    (void)GGMdisc(gp,sp);     /* Disconnect from gopher server */
  8552.  }
  8553.  
  8554.  strcpy(savebook,gp->current_bookmark_ds);
  8555.  if (EQUAL(ip->host, LOCAL_HOST_FROB)) {
  8556.    strncpy(gp->current_bookmark_ds,ip->path,sizeof(savebook));
  8557.  }
  8558.  else {
  8559.    strcpy(gp->current_bookmark_ds,"");
  8560.  }
  8561.  
  8562.  rc = (fun)(gp,ip,how);
  8563.  
  8564.  strcpy(gp->current_bookmark_ds,savebook);
  8565.  
  8566.  return rc;
  8567.  
  8568. }
  8569.  
  8570. ./ ADD NAME=GGMGSRVL
  8571.  
  8572.  /********************************************************************/
  8573.  /*                                                                  */
  8574.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8575.  /*                                                                  */
  8576.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8577.  /*                                                                  */
  8578.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8579.  /* including the implied warranties of merchantability and fitness, */
  8580.  /* are expressly denied.                                            */
  8581.  /*                                                                  */
  8582.  /* Provided this copyright notice is included, this software may    */
  8583.  /* be freely distributed and not offered for sale.                  */
  8584.  /*                                                                  */
  8585.  /* Changes or modifications may be made and used only by the maker  */
  8586.  /* of same, and not further distributed.  Such modifications should */
  8587.  /* be mailed to the author for consideration for addition to the    */
  8588.  /* software and incorporation in subsequent releases.               */
  8589.  /*                                                                  */
  8590.  /********************************************************************/
  8591.  
  8592. #pragma  csect(code,  "GG@GSRVL")
  8593. #pragma  csect(static,"GG$GSRVL")
  8594. #include "gg.h"
  8595.  
  8596. /****** Input one character from the server. *************************/
  8597.  
  8598. static int
  8599. socket_getchar(sp)
  8600. Rstruc connection *sp;
  8601. {
  8602.  int         readrc;
  8603.  
  8604.  if (sp->buf_index == -1 ||
  8605.      sp->buf_index >= sp->bytes_returned - 1) {
  8606.    sp->buf_index = -1;
  8607.    if (sp->dont_read) return(SOCKET_NO_MORE);
  8608.    else {
  8609.      TCP_DEBUG_ON;
  8610.      readrc = read(sp->ns, sp->buf, READ_BYTES);
  8611.      TCP_DEBUG_OFF;
  8612.      if (readrc == -1) {
  8613.        sp->connection_broken = TRUE;
  8614.        return SOCKET_GETCHAR_ERROR;
  8615.      }
  8616.      else if (readrc == 0) {
  8617.        sp->connection_broken = FALSE;
  8618.        return SOCKET_READ_NOTHING;
  8619.      }
  8620.      else {
  8621. #ifdef MVS
  8622.        ASCII_TO_EBCDIC(sp->buf,readrc);
  8623. #endif
  8624.        sp->bytes_returned = readrc;
  8625.      }
  8626.    }
  8627.  }
  8628.  return sp->buf[++sp->buf_index];
  8629. }
  8630.  
  8631. /****** Input one data line at a time from the server. ***************/
  8632.  
  8633. static enum socket_retval
  8634. socket_from_server(gp,sp)
  8635. Rstruc ggcb       *gp;
  8636. Rstruc connection *sp;
  8637. {
  8638.  char             *s_buf;
  8639.  int               s_bytes;
  8640.  int               s_buf_index;
  8641.  int               character;
  8642.  int               previous_character;
  8643.  
  8644.  s_buf   = sp->server_buf;
  8645.  s_bytes = SERVER_BUF_MSGSIZE;
  8646.  
  8647.  /* Get characters from the server until LF is reached. */
  8648.  
  8649.  s_buf_index = 0;
  8650.  previous_character = -1;
  8651.  for (;;) {
  8652.    character = socket_getchar(sp);
  8653.    /*
  8654.    if (character == LINE_FEED && previous_character == CARRIAGE_RETURN)
  8655.       break;
  8656.    */
  8657.    if (character == LINE_FEED) break;
  8658.    if (character == SOCKET_GETCHAR_ERROR)  return(SERVER_READ_ERROR);
  8659.    if (character == SOCKET_NO_MORE)        return(SERVER_NO_MORE);
  8660.    if (character == SOCKET_READ_NOTHING)   return(SERVER_READ_NOTHING);
  8661.    previous_character = character;
  8662.    if (s_buf_index >= s_bytes) {
  8663.      fprintf(stderr,"Error: sp->server_buf overflowed.\n");
  8664.      fprintf(stderr,
  8665.              "More than %d bytes collected without CR/LF seen.\n",
  8666.              s_bytes);
  8667.      if (gp && gp->debug_file) {
  8668.        GGMdump(gp,"Data collected so far",sp->server_buf,s_bytes);
  8669.      }
  8670.      return(SERVER_BUFFER_ERROR);
  8671.    }
  8672.    if (character == '\0' && !sp->is_ftp) {
  8673.      fprintf(stderr,
  8674. "Warning: null character found in data from server, changed to blank\n"
  8675.             );
  8676.      character = ' ';
  8677.    }
  8678.    s_buf[s_buf_index++] = (unsigned char)character;
  8679.  }
  8680.  s_buf[s_buf_index] = '\0';
  8681.  return(SERVER_READ_OK);
  8682. }
  8683.  
  8684. /****** Get server line. *********************************************/
  8685.  
  8686. Bool
  8687. GGMgsrvl(gp,sp,pointer,is_cr_needed)
  8688. Rstruc ggcb        *gp;
  8689. Rstruc connection  *sp;
  8690. char              **pointer;
  8691. Fool                is_cr_needed;
  8692. {
  8693.  char              *sbufp;
  8694.  char              *p;
  8695.  int                scan_count;
  8696.  Bool               something_to_print;
  8697.  struct recvstruct *R;
  8698.  
  8699.  if (pointer) *pointer = NULL;
  8700.  
  8701.  /* If local mode, read from temporary file until EOF. */
  8702.  
  8703.  if (gp && (R=gp->recvp) && !sp->is_ftp) {
  8704.    if (!R->outfp) {
  8705.      CRIT1("Can't read data locally, non-socket not connected\n");
  8706.      return FALSE;
  8707.    }
  8708.    fgets(sp->server_buf, SERVER_BUF_MSGSIZE, R->outfp);
  8709.    if (ferror(R->outfp)) {
  8710.      CRIT1("Error reading local non-socket data\n");
  8711.      sp->time_to_go_home = TRUE;
  8712.      return FALSE;
  8713.    }
  8714.    if (feof(R->outfp)) return FALSE;
  8715.    if ((p=strchr(sp->server_buf,'\n'))) *p = '\0';
  8716.    if (pointer) *pointer = sp->server_buf;
  8717.    return TRUE;
  8718.  }
  8719.  
  8720.  if (sp->is_ftp) {
  8721.  
  8722.    sp->time_to_go_home = FALSE;
  8723.    sp->server_has_something_pending = TRUE;
  8724.  
  8725.    switch (socket_from_server(gp,sp)) {
  8726.      case SERVER_READ_OK:      return TRUE;
  8727.      case SERVER_READ_NOTHING:
  8728.      case SERVER_NO_MORE:      sp->server_has_something_pending = FALSE;
  8729.                                return TRUE;
  8730.      case SERVER_READ_ERROR:   fprintf(stderr,
  8731.        "Lost server connection.  Failure reading data from server %s.",
  8732.                                     sp->server_hostname);
  8733.                                sp->time_to_go_home = TRUE;
  8734.                                return FALSE;
  8735.      case SERVER_BUFFER_ERROR: fprintf(stderr,
  8736.    "Read error.  No linefeed character found in data from server %s.",
  8737.                                     sp->server_hostname);
  8738.                                sp->time_to_go_home = TRUE;
  8739.                                return FALSE;
  8740.    }
  8741.  }
  8742.  
  8743.  if (!sp->receiving_text) return TRUE;
  8744.  
  8745.  if (sp->server_finished_replying) sp->dont_read = TRUE;
  8746.  
  8747.  switch (socket_from_server(gp,sp)) {
  8748.    case SERVER_READ_OK:      break;
  8749.    case SERVER_READ_NOTHING: sp->time_to_go_home = TRUE;
  8750.                              break;
  8751.    case SERVER_READ_ERROR:   ERR2(
  8752.      "Lost server connection.  Failure reading data from server %s.",
  8753.                                   sp->server_hostname);
  8754.                              sp->time_to_go_home = TRUE;
  8755.                              break;
  8756.    case SERVER_BUFFER_ERROR: ERR2(
  8757.  "Read error.  No linefeed character found in data from server %s.",
  8758.                                   sp->server_hostname);
  8759.                              sp->time_to_go_home = TRUE;
  8760.                              break;
  8761.    case SERVER_NO_MORE:      sp->server_has_something_pending = FALSE;
  8762.                              break;
  8763.  }
  8764.  
  8765.  if (sp->time_to_go_home) return FALSE;
  8766.  if (sp->dont_read && !sp->server_has_something_pending) return TRUE;
  8767.  
  8768.  something_to_print = TRUE;
  8769.  
  8770.  sbufp = sp->server_buf;
  8771.  
  8772.  if (sp->sending_text) {
  8773.    if (*sbufp == '.') {
  8774.      switch (*(sbufp+1)) {
  8775.         case CARRIAGE_RETURN:
  8776.         case LINE_FEED:
  8777.         case '\0':
  8778.                   sp->server_finished_replying = TRUE;
  8779.                   something_to_print = FALSE;
  8780.                   break;
  8781.         case '.':
  8782.                   break;
  8783.         default:  if (gp) {
  8784.                    GGMdump(gp,"Warning, bad period in line from server",
  8785.                            sbufp,strlen(sbufp));
  8786.                   }
  8787.                   break;
  8788.      }
  8789.    }
  8790.  }
  8791.  
  8792.  sp->sending_text = TRUE;
  8793.  
  8794.  if (something_to_print) {
  8795.    /* Last character of output buffer is a CR without LF. */
  8796.    p = sbufp + strlen(sbufp)-1;
  8797.    if (p >= sbufp) {
  8798.      if (*p == CARRIAGE_RETURN) *p = '\0';
  8799.      else if (is_cr_needed) {
  8800.        /* Last character of output buffer had better be a LF. */
  8801.        if (gp && gp->debug_file) {
  8802.          fprintf(gp->debug_file,
  8803.    "Warning: No carriage return in data from server (%d bytes):\n%s\n",
  8804.                strlen(sbufp), sbufp);
  8805.        }
  8806.        CRIT2(
  8807. "Carriage return expected but not seen in data from server %s.",
  8808.              sp->server_hostname);
  8809.      }
  8810.      *(p+1) = '\0';
  8811.    }
  8812.    if (pointer) *pointer = sbufp;
  8813.  }
  8814.  
  8815.  if (sp->time_to_go_home) return FALSE;
  8816.  else return TRUE;
  8817. }
  8818.  
  8819. ./ ADD NAME=GGMIERR
  8820.  
  8821.  /********************************************************************/
  8822.  /*                                                                  */
  8823.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8824.  /*                                                                  */
  8825.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8826.  /*                                                                  */
  8827.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8828.  /* including the implied warranties of merchantability and fitness, */
  8829.  /* are expressly denied.                                            */
  8830.  /*                                                                  */
  8831.  /* Provided this copyright notice is included, this software may    */
  8832.  /* be freely distributed and not offered for sale.                  */
  8833.  /*                                                                  */
  8834.  /* Changes or modifications may be made and used only by the maker  */
  8835.  /* of same, and not further distributed.  Such modifications should */
  8836.  /* be mailed to the author for consideration for addition to the    */
  8837.  /* software and incorporation in subsequent releases.               */
  8838.  /*                                                                  */
  8839.  /********************************************************************/
  8840.  
  8841. #pragma  csect(code,  "GG@IERR ")
  8842. #pragma  csect(static,"GG$IERR ")
  8843. #include "gg.h"
  8844.  
  8845. /****** ISPF error handler. ******************************************/
  8846.  
  8847. void
  8848. GGMierr(gp)
  8849. Rstruc ggcb *gp;
  8850. {
  8851.  char        errbuf[] = "DISPLAY PANEL(ISPTERM)";
  8852.  int         errlen;
  8853.  
  8854.  errlen = strlen(errbuf);
  8855.  switch (ISPEXEC(&errlen,errbuf)) {
  8856.    case  0:
  8857.    case  4:
  8858.    case  8:
  8859.            return;
  8860.    default:
  8861.            fprintf(stderr,
  8862. "\n*** Severe ISPF error, cannot even display ISPTERM error panel.\n");
  8863.            fprintf(stderr,
  8864. "\n*** Return code from ISPF service is %d\n",gp->ispfrc);
  8865.            return;
  8866.  }
  8867. }
  8868.  
  8869. ./ ADD NAME=GGMIGET
  8870.  
  8871.  /********************************************************************/
  8872.  /*                                                                  */
  8873.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8874.  /*                                                                  */
  8875.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8876.  /*                                                                  */
  8877.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8878.  /* including the implied warranties of merchantability and fitness, */
  8879.  /* are expressly denied.                                            */
  8880.  /*                                                                  */
  8881.  /* Provided this copyright notice is included, this software may    */
  8882.  /* be freely distributed and not offered for sale.                  */
  8883.  /*                                                                  */
  8884.  /* Changes or modifications may be made and used only by the maker  */
  8885.  /* of same, and not further distributed.  Such modifications should */
  8886.  /* be mailed to the author for consideration for addition to the    */
  8887.  /* software and incorporation in subsequent releases.               */
  8888.  /*                                                                  */
  8889.  /********************************************************************/
  8890.  
  8891. #pragma  csect(code,  "GG@IGET ")
  8892. #pragma  csect(static,"GG$IGET ")
  8893. #include "gg.h"
  8894.  
  8895. /****** Retrieve the value of an ISPF variable into an integer. ******/
  8896.  
  8897. int
  8898. GGMiget(gp,varname)
  8899. Rstruc ggcb *gp;
  8900. char        *varname;
  8901. {
  8902.  char        varbuf[16];
  8903.  int         vcopy_length;
  8904.  
  8905.  if (!strchr(varname,' ')) {
  8906.    fprintf(stderr,"GGMiget: no blank passed in var name\n");
  8907.    return FALSE;
  8908.  }
  8909.  
  8910.  vcopy_length = sizeof(varbuf);
  8911.  
  8912.  gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
  8913.  switch (gp->ispfrc) {
  8914.    case  0:
  8915.            varbuf[vcopy_length] = '\0';
  8916.            return atoi(varbuf);
  8917.    case  8:
  8918.            return 0;
  8919.    case 16:
  8920.            fprintf(stderr,
  8921.                    "Error: ISPF variable buffer too short to get %s\n",
  8922.                    varname);
  8923.            return 0;
  8924.    default:
  8925.            GGMierr(gp);   /* handle ISPF error */
  8926.            return 0;
  8927.  }
  8928. }
  8929.  
  8930. ./ ADD NAME=GGMINFO
  8931.  
  8932.  /********************************************************************/
  8933.  /*                                                                  */
  8934.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8935.  /*                                                                  */
  8936.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8937.  /*                                                                  */
  8938.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8939.  /* including the implied warranties of merchantability and fitness, */
  8940.  /* are expressly denied.                                            */
  8941.  /*                                                                  */
  8942.  /* Provided this copyright notice is included, this software may    */
  8943.  /* be freely distributed and not offered for sale.                  */
  8944.  /*                                                                  */
  8945.  /* Changes or modifications may be made and used only by the maker  */
  8946.  /* of same, and not further distributed.  Such modifications should */
  8947.  /* be mailed to the author for consideration for addition to the    */
  8948.  /* software and incorporation in subsequent releases.               */
  8949.  /*                                                                  */
  8950.  /********************************************************************/
  8951.  
  8952. #pragma  csect(code,  "GG@INFO ")
  8953. #pragma  csect(static,"GG$INFO ")
  8954. #include "gg.h"
  8955.  
  8956.  
  8957. /****** Gopher it. ***************************************************/
  8958.  
  8959. Bool
  8960. GGMinfo(gp,ip)
  8961. Rstruc ggcb        *gp;
  8962. Rstruc gopherinfo  *ip;
  8963. {
  8964.  char               buf [513];
  8965.  
  8966.  if (!ip) {
  8967.    ERR1("Info is not available - this is not a Gopher item.");
  8968.    return FALSE;
  8969.  }
  8970.  
  8971.  GGMclrtx(gp,NULL);
  8972.  
  8973.  sprintf(buf,"");                        GGMouttx(gp,buf,NULL);
  8974.  sprintf(buf,"Type=%c",ip->type);        GGMouttx(gp,buf,NULL);
  8975.  sprintf(buf,"Name=%s",ip->desc);        GGMouttx(gp,buf,NULL);
  8976.  sprintf(buf,"Path=%s",ip->path);        GGMouttx(gp,buf,NULL);
  8977.  sprintf(buf,"Host=%s",ip->host);        GGMouttx(gp,buf,NULL);
  8978.  sprintf(buf,"Port=%d",ip->port);        GGMouttx(gp,buf,NULL);
  8979.  sprintf(buf,"End");                     GGMouttx(gp,buf,NULL);
  8980.  
  8981.  return TRUE;
  8982. }
  8983.  
  8984. ./ ADD NAME=GGMISPF
  8985.  
  8986.  /********************************************************************/
  8987.  /*                                                                  */
  8988.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  8989.  /*                                                                  */
  8990.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  8991.  /*                                                                  */
  8992.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  8993.  /* including the implied warranties of merchantability and fitness, */
  8994.  /* are expressly denied.                                            */
  8995.  /*                                                                  */
  8996.  /* Provided this copyright notice is included, this software may    */
  8997.  /* be freely distributed and not offered for sale.                  */
  8998.  /*                                                                  */
  8999.  /* Changes or modifications may be made and used only by the maker  */
  9000.  /* of same, and not further distributed.  Such modifications should */
  9001.  /* be mailed to the author for consideration for addition to the    */
  9002.  /* software and incorporation in subsequent releases.               */
  9003.  /*                                                                  */
  9004.  /********************************************************************/
  9005.  
  9006. #pragma  csect(code,  "GG@ISPF ")
  9007. #pragma  csect(static,"GG$ISPF ")
  9008. #include "gg.h"
  9009.  
  9010. /****** Call ISPF service. *******************************************/
  9011.  
  9012. Bool
  9013. GGMispf(gp,ispfbuf)
  9014. Rstruc ggcb *gp;
  9015. char        *ispfbuf;
  9016. {
  9017.  int         ispflen = strlen(ispfbuf);
  9018.  
  9019.  if (!gp) return TRUE;
  9020.  
  9021. #ifndef ISPFV2
  9022.  if (gp->test_mode) {
  9023. #endif
  9024.    if (ispflen >= 6
  9025.       && (memcmp(ispfbuf,"ADDPOP",6) == 0
  9026.        || memcmp(ispfbuf,"REMPOP",6) == 0)) {
  9027.      gp->ispfrc = 0;
  9028.      return TRUE;
  9029.    }
  9030. #ifndef ISPFV2
  9031.  }
  9032. #endif
  9033.  
  9034.  gp->ispfrc = ISPEXEC(&ispflen,ispfbuf);
  9035.  if (gp->ispfrc > 8) {
  9036.  
  9037.    /* Ignore ADDPOP and REMPOP errors, especially if they are due to
  9038.       ISPF V3 not being active. */
  9039.  
  9040.    if (gp->ispfrc == 20
  9041.     && gp->debug_mode == FALSE
  9042.     && ispflen >= 6
  9043.     && (memcmp(ispfbuf,"ADDPOP",6) == 0
  9044.      || memcmp(ispfbuf,"REMPOP",6) == 0)) {
  9045.      return TRUE;
  9046.    }
  9047.  
  9048.    GGMierr(gp);             /* handle ISPF error */
  9049.    return FALSE;
  9050.  }
  9051.  return TRUE;
  9052. }
  9053.  
  9054. ./ ADD NAME=GGMIVGET
  9055.  
  9056.  /********************************************************************/
  9057.  /*                                                                  */
  9058.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9059.  /*                                                                  */
  9060.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9061.  /*                                                                  */
  9062.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9063.  /* including the implied warranties of merchantability and fitness, */
  9064.  /* are expressly denied.                                            */
  9065.  /*                                                                  */
  9066.  /* Provided this copyright notice is included, this software may    */
  9067.  /* be freely distributed and not offered for sale.                  */
  9068.  /*                                                                  */
  9069.  /* Changes or modifications may be made and used only by the maker  */
  9070.  /* of same, and not further distributed.  Such modifications should */
  9071.  /* be mailed to the author for consideration for addition to the    */
  9072.  /* software and incorporation in subsequent releases.               */
  9073.  /*                                                                  */
  9074.  /********************************************************************/
  9075.  
  9076. #pragma  csect(code,  "GG@IVGET")
  9077. #pragma  csect(static,"GG$IVGET")
  9078. #include "gg.h"
  9079.  
  9080. /****** Retrieve the value of an ISPF variable. **********************/
  9081.  
  9082. Bool
  9083. GGMivget(gp,varname,varbuf,varbuflen)
  9084. Rstruc ggcb *gp;
  9085. char        *varname;
  9086. char        *varbuf;
  9087. int          varbuflen;
  9088. {
  9089.  int         vcopy_length;
  9090.  
  9091.  if (!strchr(varname,' ')) {
  9092.    fprintf(stderr,"GGMivget: no blank passed in var name\n");
  9093.    return FALSE;
  9094.  }
  9095.  
  9096.  /*
  9097.   * If varbuflen is negative, that means that the value is not to be
  9098.   * treated as a C string, and the null character is not to be
  9099.   * appended to the resulting value.  This is used for hex values
  9100.   * (like addresses) that are stored in ISPF table row variables.
  9101.   */
  9102.  
  9103.  if (varbuflen < 0)  vcopy_length = -varbuflen;
  9104.  else vcopy_length = varbuflen;
  9105.  
  9106.  /* Note that on entry, vcopy_length is an integer that contains
  9107.     the length of the buffer.  On return it is updated to the length
  9108.     of the value returned.  Since we have to stick a null character
  9109.     on the end of it for C, the actual buffer passed must be at least
  9110.     one character longer than the length as defined to ISPF.
  9111.  */
  9112.  
  9113.  gp->ispfrc = ISPLINK("VCOPY",varname,&vcopy_length,varbuf,"MOVE");
  9114.  switch (gp->ispfrc) {
  9115.    case  0:
  9116.            if (varbuflen >= 0)
  9117.               varbuf[vcopy_length] = '\0';
  9118.            return TRUE;
  9119.    case  8:
  9120.            strcpy(varbuf,"");
  9121.            return TRUE;
  9122.    case 16:
  9123.            fprintf(stderr,
  9124.                    "Error: ISPF variable buffer too short to get %s\n",
  9125.                    varname);
  9126.            return FALSE;
  9127.    default:
  9128.            GGMierr(gp);   /* handle ISPF error */
  9129.            return FALSE;
  9130.  }
  9131. }
  9132.  
  9133. ./ ADD NAME=GGMIVPUT
  9134.  
  9135.  /********************************************************************/
  9136.  /*                                                                  */
  9137.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9138.  /*                                                                  */
  9139.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9140.  /*                                                                  */
  9141.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9142.  /* including the implied warranties of merchantability and fitness, */
  9143.  /* are expressly denied.                                            */
  9144.  /*                                                                  */
  9145.  /* Provided this copyright notice is included, this software may    */
  9146.  /* be freely distributed and not offered for sale.                  */
  9147.  /*                                                                  */
  9148.  /* Changes or modifications may be made and used only by the maker  */
  9149.  /* of same, and not further distributed.  Such modifications should */
  9150.  /* be mailed to the author for consideration for addition to the    */
  9151.  /* software and incorporation in subsequent releases.               */
  9152.  /*                                                                  */
  9153.  /********************************************************************/
  9154.  
  9155. #pragma  csect(code,  "GG@IVPUT")
  9156. #pragma  csect(static,"GG$IVPUT")
  9157. #include "gg.h"
  9158.  
  9159. /****** Set the value of an ISPF variable. ***************************/
  9160.  
  9161. Bool
  9162. GGMivput(gp,varname,varbuf,varlen)
  9163. Rstruc ggcb *gp;
  9164. char        *varname;
  9165. char        *varbuf;
  9166. int          varlen;
  9167. {
  9168.  int         vreplace_length;
  9169.  
  9170.  vreplace_length = (varlen<0 ? strlen(varbuf) : varlen);
  9171.  
  9172.  gp->ispfrc = ISPLINK("VREPLACE",varname,&vreplace_length,varbuf);
  9173.  switch (gp->ispfrc) {
  9174.    case  0:
  9175.            return TRUE;
  9176.    case 16:
  9177.            fprintf(stderr,
  9178.                    "Error: ISPF variable buffer too short to put %s\n",
  9179.                    varname);
  9180.            return FALSE;
  9181.    default:
  9182.            GGMierr(gp);   /* handle ISPF error */
  9183.            return FALSE;
  9184.  }
  9185. }
  9186.  
  9187. ./ ADD NAME=GGMMENU
  9188.  
  9189.  /********************************************************************/
  9190.  /*                                                                  */
  9191.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9192.  /*                                                                  */
  9193.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9194.  /*                                                                  */
  9195.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9196.  /* including the implied warranties of merchantability and fitness, */
  9197.  /* are expressly denied.                                            */
  9198.  /*                                                                  */
  9199.  /* Provided this copyright notice is included, this software may    */
  9200.  /* be freely distributed and not offered for sale.                  */
  9201.  /*                                                                  */
  9202.  /* Changes or modifications may be made and used only by the maker  */
  9203.  /* of same, and not further distributed.  Such modifications should */
  9204.  /* be mailed to the author for consideration for addition to the    */
  9205.  /* software and incorporation in subsequent releases.               */
  9206.  /*                                                                  */
  9207.  /********************************************************************/
  9208.  
  9209. #pragma  csect(code,  "GG@MENU ")
  9210. #pragma  csect(static,"GG$MENU ")
  9211. #include "gg.h"
  9212.  
  9213. /****** Display Gopher menu in data set. *****************************/
  9214.  
  9215. Bool
  9216. GGMmenu(gp,pp)
  9217. Rstruc ggcb             *gp;
  9218. char                    *pp;
  9219. {
  9220.  struct gopherinfo      *ip;
  9221.  struct gopherinfo      *saveip;
  9222.  char                   *cp;
  9223.  Bool                    rc;
  9224.  char                    zprefix[9];
  9225.  char                    temp[129];
  9226.  char                    savebook[63];
  9227.  
  9228.  if (!*pp) {
  9229.    ERR1("You must supply a data set name for a Gopher menu.");
  9230.    return FALSE;
  9231.  }
  9232.  
  9233.  if (strlen(pp) >= sizeof(temp)) {
  9234.    ERR1("Gopher menu name too long");
  9235.    return FALSE;
  9236.  }
  9237.  
  9238.  GETMAIN(ip, struct gopherinfo, 1, "menu gopherinfo struct");
  9239.  if (!ip) {
  9240.    ERR2("Not enough memory to load Gopher menu %s",pp);
  9241.    return FALSE;
  9242.  }
  9243.  
  9244.  memset(ip,0,sizeof(struct gopherinfo));
  9245.  
  9246.  
  9247.  copy_uppercase(temp,pp);
  9248.  
  9249.  if (temp[0] == '\'') {
  9250.    strcpy(ip->path, temp+1);
  9251.    cp = &ip->path[strlen(ip->path)-1];
  9252.    if (*cp == '\'') *cp = '\0';
  9253.  }
  9254.  else {
  9255.    GGMivget(gp,"ZPREFIX ",zprefix,sizeof(zprefix));
  9256.    if (!*zprefix)  sprintf(ip->path,"'%s'",pp);
  9257.    else sprintf(ip->path,"%s.%s",zprefix,pp);
  9258.  }
  9259.  
  9260.  ip->type = MENU;
  9261.  sprintf(ip->desc,"User menu %s",ip->path);
  9262.  strcpy (ip->host, "-");
  9263.  ip->port = SERV_TCP_PORT;
  9264.  
  9265.  saveip = gp->ginfo;
  9266.  gp->ginfo = ip;
  9267.  strcpy(savebook,gp->current_bookmark_ds);
  9268.  strncpy(gp->current_bookmark_ds,ip->path,sizeof(savebook));
  9269.  
  9270.  rc = GGMgofor(gp,ip,AS_NORMAL);
  9271.  
  9272.  gp->ginfo = saveip;
  9273.  strcpy(gp->current_bookmark_ds,savebook);
  9274.  
  9275.  FREEMAIN(ip,"menu gopherinfo struct");
  9276.  
  9277.  return rc;
  9278. }
  9279.  
  9280. ./ ADD NAME=GGMMTFER
  9281.  
  9282.  /********************************************************************/
  9283.  /*                                                                  */
  9284.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9285.  /*                                                                  */
  9286.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9287.  /*                                                                  */
  9288.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9289.  /* including the implied warranties of merchantability and fitness, */
  9290.  /* are expressly denied.                                            */
  9291.  /*                                                                  */
  9292.  /* Provided this copyright notice is included, this software may    */
  9293.  /* be freely distributed and not offered for sale.                  */
  9294.  /*                                                                  */
  9295.  /* Changes or modifications may be made and used only by the maker  */
  9296.  /* of same, and not further distributed.  Such modifications should */
  9297.  /* be mailed to the author for consideration for addition to the    */
  9298.  /* software and incorporation in subsequent releases.               */
  9299.  /*                                                                  */
  9300.  /********************************************************************/
  9301.  
  9302. #pragma  csect(code,  "GG@MTFER")
  9303. #pragma  csect(static,"GG$MTFER")
  9304. #include "gg.h"
  9305.  
  9306. /*********************************************************************/
  9307.  
  9308. void
  9309. GGMmtfer(
  9310.          int          retcode,
  9311.          char        *kind)
  9312. {
  9313.  char    *ermsg;
  9314.  
  9315.  switch (retcode) {
  9316.    case MTF_OK:
  9317.         ermsg = NULL;
  9318.         break;
  9319.    case EINACTIVE:
  9320.         ermsg = "MTF is inactive";
  9321.         break;
  9322.    case ESUBCALL:
  9323.         ermsg = "The MTF call was issued from a subtask";
  9324.         break;
  9325.    case EWRONGOS:
  9326.         ermsg = "MTF is not supported under CMS, IMS, CICS, or DB2";
  9327.         break;
  9328.    case EACTIVE:
  9329.         ermsg = "MTF has already been initialized and is active";
  9330.         break;
  9331.    case ENAME2LNG:
  9332.         ermsg = "The parallel module name is longer than 8 characters";
  9333.         break;
  9334.    case ETASKNUM:
  9335.         ermsg = "The number of tasks specified is invalid";
  9336.         break;
  9337.    case ENOMEM:
  9338.         ermsg = "Insufficient storage for MTF internal areas";
  9339.         break;
  9340.    case EMODFIND:
  9341.         ermsg = "The parallel load module was not found";
  9342.         break;
  9343.    case EMODREAD:
  9344.         ermsg = "The parallel load module was not sucessfully read";
  9345.         break;
  9346.    case EMODFMT:
  9347.         ermsg = "The parallel load module format is invalid";
  9348.         break;
  9349.    case EAUTOALC:
  9350.         ermsg = "Automatic allocation of standard stream DD failed";
  9351.         break;
  9352.    case ETASKFAIL:
  9353.         ermsg = "The attempt to attach task(s) has failed";
  9354.         break;
  9355.    case ETASKABND:
  9356.         ermsg = "One or more subtasks have abnormally terminated";
  9357.         break;
  9358.    case EBADLNKG:
  9359.         ermsg = "TSCHED has been invoked via invalid linkage";
  9360.         break;
  9361.    case ETASKID:
  9362.         ermsg = "The task ID specified is not valid";
  9363.         break;
  9364.    case EENTRY:
  9365.         ermsg = "The parallel function was not in the parallel module";
  9366.         break;
  9367.    default:
  9368.         ermsg = "Unknown MTF error";
  9369.         break;
  9370.  }
  9371.  
  9372.  if (ermsg) {
  9373.    fprintf(stderr,"GGSERVER: %s error code %d:\n %s\n",
  9374.                   kind, retcode, ermsg);
  9375.  }
  9376.  
  9377.  return;
  9378.  
  9379. }
  9380.  
  9381. ./ ADD NAME=GGMOUTS
  9382.  
  9383.  /********************************************************************/
  9384.  /*                                                                  */
  9385.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9386.  /*                                                                  */
  9387.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9388.  /* including the implied warranties of merchantability and fitness, */
  9389.  /* are expressly denied.                                            */
  9390.  /*                                                                  */
  9391.  /* Provided this copyright notice is included, this software may    */
  9392.  /* be freely distributed and not offered for sale.                  */
  9393.  /*                                                                  */
  9394.  /* Changes or modifications may be made and used only by the maker  */
  9395.  /* of same, and not further distributed.  Such modifications should */
  9396.  /* be mailed to the author for consideration for addition to the    */
  9397.  /* software and incorporation in subsequent releases.               */
  9398.  /*                                                                  */
  9399.  /********************************************************************/
  9400.  
  9401. #pragma  csect(code,  "GG@MOUTS")
  9402. #pragma  csect(static,"GG$MOUTS")
  9403.  
  9404. #include "gg.h"
  9405. /*
  9406.  ***********************************************************************
  9407.  *                                                                     *
  9408.  * This is a Gopher server routine that outputs data to a socket.      *
  9409.  *                                                                     *
  9410.  * If the "socket" is actually a file pointer, then output is          *
  9411.  * written to the file pointer.                                        *
  9412.  *                                                                     *
  9413.  ***********************************************************************
  9414.  */
  9415.  
  9416. /*=================================================================*/
  9417.  
  9418. Bool
  9419. GGMouts(struct recvstruct *R,
  9420.         char              *text)
  9421. {
  9422.  int                len;
  9423.  int                reallen;
  9424.  Bool               rc;
  9425.  char               outbuf[515];  /* hold an output character string */
  9426.  
  9427.  if (R->outfp) {                    /* if using non-socket interface */
  9428.    if (fputs(text,R->outfp) < 0) {
  9429.      fprintf(stderr,"Error writing to output file\n");
  9430.      return FALSE;
  9431.    }
  9432.    if (fputc('\n',R->outfp) < 0) {
  9433.      fprintf(stderr,"Error writing to output file\n");
  9434.      return FALSE;
  9435.    }
  9436.    return TRUE;
  9437.  }
  9438.  
  9439.  if (text == NULL) {
  9440.    outbuf[0] = '.';
  9441.    len = 1;
  9442.  }
  9443.  else {
  9444.    len = strlen(text);
  9445.    if (len >= sizeof(outbuf)-3) len = sizeof(outbuf)-3;
  9446.    if (text[0] == '.') {
  9447.      outbuf[0] = '.';
  9448.      memcpy(outbuf+1,text,len);
  9449.      len++;
  9450.    }
  9451.    else {
  9452.      memcpy(outbuf,text,len);
  9453.    }
  9454.  }
  9455.  outbuf[len  ] = CARRIAGE_RETURN;
  9456.  outbuf[len+1] = LINE_FEED;
  9457.  outbuf[len+2] = '\0';
  9458.  reallen = len + 2;
  9459.  
  9460. #ifdef SNSTCPIP
  9461.  EBCDIC_TO_ASCII(outbuf,reallen);
  9462. #else
  9463.  ebdtoasc(outbuf);
  9464. #endif
  9465.  
  9466.  rc = TRUE;
  9467.  
  9468.  if (R->outlen + reallen > sizeof(R->sockbuf)) {
  9469.  
  9470.    if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
  9471.      REPORT_TCP_ERROR("SEND");
  9472.      rc = FALSE;
  9473.    }
  9474.    R->outlen = 0;
  9475.  }
  9476.  
  9477.  memcpy(R->sockbuf + R->outlen, outbuf, reallen);
  9478.  R->outlen += reallen;
  9479.  
  9480.  if (text == NULL) {  /* flush socket */
  9481.    if (write(R->sockfd,R->sockbuf,R->outlen) < 0) {
  9482.      REPORT_TCP_ERROR("SEND");
  9483.      rc = FALSE;
  9484.    }
  9485.  }
  9486.  return rc;
  9487. }
  9488.  
  9489. ./ ADD NAME=GGMOUTTX
  9490.  
  9491.  /********************************************************************/
  9492.  /*                                                                  */
  9493.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9494.  /*                                                                  */
  9495.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9496.  /*                                                                  */
  9497.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9498.  /* including the implied warranties of merchantability and fitness, */
  9499.  /* are expressly denied.                                            */
  9500.  /*                                                                  */
  9501.  /* Provided this copyright notice is included, this software may    */
  9502.  /* be freely distributed and not offered for sale.                  */
  9503.  /*                                                                  */
  9504.  /* Changes or modifications may be made and used only by the maker  */
  9505.  /* of same, and not further distributed.  Such modifications should */
  9506.  /* be mailed to the author for consideration for addition to the    */
  9507.  /* software and incorporation in subsequent releases.               */
  9508.  /*                                                                  */
  9509.  /********************************************************************/
  9510.  
  9511. #pragma  csect(code,  "GG@OUTTX")
  9512. #pragma  csect(static,"GG$OUTTX")
  9513. #include "gg.h"
  9514.  
  9515. /****** Output a line of text retrieved from the server. *************/
  9516.  
  9517. struct textline *
  9518. GGMouttx(gp,line,ip)
  9519. Rstruc ggcb         *gp;
  9520. char                *line;
  9521. Rstruc gopherinfo   *ip;
  9522.  
  9523. {
  9524.  struct texthdr     *thp;
  9525.  struct textline    *tp;
  9526.  short              line_length;
  9527.  short              total_text_length;
  9528.  short              tab_expansion_length;
  9529.  Bool               tabs_present;
  9530.  char              *p;
  9531.  char              *q;
  9532.  char              *t;
  9533.  int                e;
  9534.  int                u;
  9535.  
  9536.  static char        tab_expansion_buffer[8*TEXT_BYTES];
  9537.  
  9538.  thp = (ip ? &ip->thdr : &gp->thdr);
  9539.  
  9540.  /* If line starts with double period, make it a single period. */
  9541.  
  9542.  if (ip && memcmp(line,"..",2) == 0) line++;
  9543.  
  9544.  /* Add this line to the current queue of server text lines. */
  9545.  
  9546.  /* First, expand tabs in the line. */
  9547.  
  9548.  line_length = strlen(line);
  9549.  t = strchr(line,'\t');
  9550.  if (t == NULL) {
  9551.    tabs_present = FALSE;
  9552.    total_text_length = line_length + 1;
  9553.  }
  9554.  else {                                   /* expand tabs */
  9555.    tabs_present = TRUE;
  9556.    p = line;
  9557.    q = line + line_length;
  9558.    e = 0;
  9559.    memset(tab_expansion_buffer,' ',sizeof(tab_expansion_buffer));
  9560.    while (TRUE) {
  9561.      u = t-p;
  9562.      if (u > 0) {
  9563.        memcpy(tab_expansion_buffer+e,p,u);
  9564.        e += u;
  9565.      }
  9566.      if (t == q) break;
  9567.      e = e / 8 * 8 + 8;
  9568.      p = t+1;
  9569.      t = strchr(p,'\t');
  9570.      if (t == NULL) t = q;
  9571.    }
  9572.    tab_expansion_length = e;
  9573.    tab_expansion_buffer[tab_expansion_length] = '\0';
  9574.    total_text_length = line_length + tab_expansion_length + 1;
  9575.  }
  9576.  
  9577.  GETMAIN(tp, char, offsetof(struct textline, text) + total_text_length,
  9578.                    "text line");
  9579.  
  9580.  if (tp == NULL) {
  9581.    ERR1("There is not enough virtual storage to process server text.");
  9582.    return NULL;
  9583.  }
  9584.  
  9585.  tp->next = NULL;
  9586.  tp->text_length = line_length;
  9587.  strcpy(tp->text,line);
  9588.  if (tabs_present) {
  9589.    tp->tab_expanded_text_length = tab_expansion_length;
  9590.    tp->tab_expanded_text = tp->text + line_length;
  9591.    strcpy(tp->tab_expanded_text,tab_expansion_buffer);
  9592.  }
  9593.  else {
  9594.    tp->tab_expanded_text_length = line_length;
  9595.    tp->tab_expanded_text = tp->text;
  9596.  }
  9597.  
  9598.  if (thp->last_text_line == NULL) {
  9599.    thp->first_text_line   = tp;
  9600.    thp->text_body_line    = tp;
  9601.    thp->current_text_line = tp;
  9602.  }
  9603.  else thp->last_text_line->next = tp;
  9604.  
  9605.  thp->last_text_line = tp;
  9606.  thp->text_line_count++;
  9607.  
  9608.  if (thp->text_max_length < tp->text_length)
  9609.      thp->text_max_length = tp->text_length;
  9610.  if (thp->text_max_tab_expanded_length < tp->tab_expanded_text_length)
  9611.      thp->text_max_tab_expanded_length = tp->tab_expanded_text_length;
  9612.  
  9613.  return tp;
  9614.  
  9615. }
  9616.  
  9617. ./ ADD NAME=GGMPMSG
  9618.  
  9619.  /********************************************************************/
  9620.  /*                                                                  */
  9621.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  9622.  /*                                                                  */
  9623.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9624.  /*                                                                  */
  9625.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9626.  /* including the implied warranties of merchantability and fitness, */
  9627.  /* are expressly denied.                                            */
  9628.  /*                                                                  */
  9629.  /* Provided this copyright notice is included, this software may    */
  9630.  /* be freely distributed and not offered for sale.                  */
  9631.  /*                                                                  */
  9632.  /* Changes or modifications may be made and used only by the maker  */
  9633.  /* of same, and not further distributed.  Such modifications should */
  9634.  /* be mailed to the author for consideration for addition to the    */
  9635.  /* software and incorporation in subsequent releases.               */
  9636.  /*                                                                  */
  9637.  /********************************************************************/
  9638.  
  9639. #define  SUPPRESS_V_DECLARATION
  9640. #pragma  csect(code,  "GG@PMSG ")
  9641. #pragma  csect(static,"GG$PMSG ")
  9642. #include "gg.h"
  9643.  
  9644. /****** Set an ISPF message, or write to SYSOUT if batch mode. *******/
  9645.  
  9646. void
  9647. GGMpmsg(gp,msgtype,msghelp,msgformat) /* also ... for sprintf args */
  9648. Rstruc ggcb *gp;
  9649. int          msgtype;
  9650. char        *msghelp;
  9651. char        *msgformat;
  9652. {
  9653.  va_list     argp;
  9654.  char       *cp;
  9655.  char        zerrsm    [25];
  9656.  char        zerrhm     [9];
  9657.  char        zerralrm   [4];
  9658.  char        zerrlm   [ZERRLM_SIZE];
  9659.  char        buf      [257];
  9660.  
  9661.  va_start(argp,msgformat);
  9662.  vsprintf(buf,msgformat,argp);
  9663.  va_end(argp);
  9664.  
  9665.  cp = strchr(buf,';');
  9666.  if (cp) {
  9667.   *cp = '\0';
  9668.   strncpy(zerrsm,buf, sizeof(zerrsm));
  9669.   strncpy(zerrlm,cp+1,sizeof(zerrlm));
  9670.  }
  9671.  else {
  9672.   strcpy(zerrsm,"");
  9673.   strncpy(zerrlm,buf,sizeof(zerrlm));
  9674.  }
  9675.  
  9676.  zerrsm[sizeof(zerrsm)-1] = '\0';
  9677.  zerrlm[sizeof(zerrlm)-1] = '\0';
  9678.  
  9679.  if (msghelp) strcpy(zerrhm, msghelp);
  9680.  else         strcpy(zerrhm, "*"    );
  9681.  
  9682.  switch (msgtype) {
  9683.    case NOTIFY_MSG:    strcpy(zerralrm,"NO "); break;
  9684.    case WARNING_MSG:
  9685.    case CRITICAL_MSG:
  9686.    default:            strcpy(zerralrm,"YES"); break;
  9687.  }
  9688.  
  9689.  (void)GGMivput(gp,"ZERRSM ",  zerrsm,   -1);
  9690.  (void)GGMivput(gp,"ZERRLM ",  zerrlm,   -1);
  9691.  (void)GGMivput(gp,"ZERRHM ",  zerrhm,   -1);
  9692.  (void)GGMivput(gp,"ZERRALRM ",zerralrm, -1);
  9693.  
  9694.  gp->setmsg = TRUE;
  9695.  
  9696.  return;
  9697. }
  9698.  
  9699. ./ ADD NAME=GGMPROC
  9700.  
  9701.  /********************************************************************/
  9702.  /*                                                                  */
  9703.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  9704.  /*                                                                  */
  9705.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  9706.  /* including the implied warranties of merchantability and fitness, */
  9707.  /* are expressly denied.                                            */
  9708.  /*                                                                  */
  9709.  /* Provided this copyright notice is included, this software may    */
  9710.  /* be freely distributed and not offered for sale.                  */
  9711.  /*                                                                  */
  9712.  /* Changes or modifications may be made and used only by the maker  */
  9713.  /* of same, and not further distributed.  Such modifications should */
  9714.  /* be mailed to the author for consideration for addition to the    */
  9715.  /* software and incorporation in subsequent releases.               */
  9716.  /*                                                                  */
  9717.  /********************************************************************/
  9718.  
  9719. #pragma  csect(code,  "GG@MPROC")
  9720. #pragma  csect(static,"GG$MPROC")
  9721.  
  9722. #pragma  linkage(IRXEXEC,OS)
  9723.  
  9724. #include "gg.h"
  9725.  
  9726. /**********************************************************************
  9727.  *                                                                    *
  9728.  * Changes: 02/17/93 Fixed memcmp logic in append-domain-name code.   *
  9729.  *          06/15/93 Added remote FTP facility via "ftp:" path hack.  *
  9730.  *                                                                    *
  9731.  **********************************************************************/
  9732.  
  9733. #define CLOSETEMP(A) \
  9734.  if (fclose(A) < 0) {\
  9735.    fprintf(stderr, \
  9736.     "GOPHER: Can't close temporary file for remote FTP request\n");\
  9737.    gbarf(R, \
  9738.           "the GOPHER server couldn't service the remote FTP request");\
  9739.    return FALSE;\
  9740.  }
  9741.  
  9742. #define REMOVETEMP(A) \
  9743.  if (remove(A) < 0) { \
  9744.    fprintf(stderr, \
  9745.     "GOPHER: Can't remove temporary file for remote FTP request\n");\
  9746.    gbarf(R, \
  9747.           "the GOPHER server couldn't service the remote FTP request");\
  9748.    return FALSE;\
  9749.  }
  9750.  
  9751. /*=================================================================*/
  9752.  
  9753. /*******************************************************************/
  9754. /*   This routine cleans up a token.  It converts all chars to     */
  9755. /*   upper case and removes any leading spaces. Note that the      */
  9756. /*   string is assumed to be null terminated.                      */
  9757. /*                                                                 */
  9758. /*       INPUT    token          pointer to token string.          */
  9759. /*       OUTPUT   *token         string upcased, blanks removed.   */
  9760. /*******************************************************************/
  9761.  
  9762. static char *
  9763. uppercase_and_trim_leading_space(char *token)
  9764. {
  9765.  
  9766.  uppercase_in_place(token);
  9767.  
  9768.  return token + strspn(token," ");
  9769. };
  9770.  
  9771. /*=================================================================*/
  9772.  
  9773. /****************************************************/
  9774. /* This routine "cleans" a string by removing the   */
  9775. /* leading spaces and trailing spaces+non-printable */
  9776. /* characters.                                      */
  9777. /****************************************************/
  9778.  
  9779. static char *
  9780. trim_leading_and_trailing_space(char *string)
  9781. {
  9782. char *str;
  9783. char *ptr;
  9784.  
  9785.  /*  first clean up the beginning of the string... */
  9786.  
  9787.  str = string + strspn(string," \t");
  9788.  
  9789.  /*    now look at the end of the string... */
  9790.  
  9791.  ptr = str+strlen(str)-1;
  9792.  while (!isgraph(*ptr) && ptr >=str) ptr--;
  9793.  *(ptr+1)=0;
  9794.  
  9795.  return str;
  9796. }
  9797.  
  9798. /*=================================================================*/
  9799.  
  9800. /****************************************************/
  9801. /* This routine "cleans" an output line by removing */
  9802. /* trailing spaces and non-printable characters.    */
  9803. /****************************************************/
  9804.  
  9805. static void
  9806. trim_trailing_space(char *string)
  9807. {
  9808.  char *ptr;
  9809.  
  9810.  ptr = string;
  9811.  
  9812.  /*  look at the end of the string... */
  9813.  
  9814.  ptr = string+strlen(string)-1;
  9815.  while (isgraph(*ptr)==0 && ptr >=string) ptr--;
  9816.  *(ptr+1)=0;
  9817. }
  9818.  
  9819. /*=================================================================*/
  9820.  
  9821. static void
  9822. gbarf(struct recvstruct *R,
  9823.       char              *message)
  9824. {
  9825.  char        temp[257];
  9826.  
  9827.  /* the number should be 3 (ERROR) but some clients may not show it
  9828.   *             |
  9829.   *             |
  9830.   *             |
  9831.   *             V
  9832.   */
  9833.  sprintf(temp, "1Sorry, %s.\t0\t0\t0", message);
  9834.  
  9835.  (void)GGMouts(R,temp);
  9836.  
  9837.  return;
  9838. }
  9839.  
  9840. /*=================================================================*/
  9841.  
  9842. static Bool
  9843. insure_my_name(struct recvstruct *R)
  9844. {
  9845.  int                hostlen;
  9846.  int                domslen;
  9847.  
  9848.  /* Determine the local path name, if not already set. */
  9849.  
  9850.  if (!*R->myname) {
  9851.    if (gethostname(R->myname,MAXHOSTNAMELEN) < 0) {
  9852.      fprintf(stderr,"GOPHER:gethostname() failed, can't get my name\n");
  9853.      gbarf(R,"the GOPHER server had an attack of amnesia");
  9854.      return FALSE;
  9855.    }
  9856.  
  9857. #ifdef APPEND_DOMAIN_NAME_TO_SELF
  9858.  
  9859.    hostlen = strlen(R->myname);
  9860.    domslen = strlen(R->mydomain);
  9861.    if (hostlen <= domslen ||
  9862.       memcmp(R->myname+hostlen-domslen, R->mydomain, domslen)) {
  9863.      strncat(R->myname, R->mydomain, domslen);
  9864.    }
  9865.  
  9866. #endif
  9867.  
  9868.    uppercase_in_place(R->myname);
  9869.  
  9870.    /* fprintf(stderr,"Local hostname set to '%s'\n",R->myname); */
  9871.  
  9872.  }
  9873.  
  9874.  return TRUE;
  9875.  
  9876. }
  9877.  
  9878. /*=================================================================*/
  9879.  
  9880. static FILE *
  9881. create_temporary_file(struct recvstruct *R,
  9882.                       char              *tempdsn
  9883.                      )
  9884. {
  9885.  FILE       *ftpfp = NULL;
  9886.  
  9887.  if (!tmpnam(tempdsn)) {
  9888.    fprintf(stderr,
  9889.     "GOPHER: Can't create temporary file for remote FTP request\n");
  9890.    return NULL;
  9891.  }
  9892.  
  9893.  ftpfp = fopen(tempdsn,
  9894.                "w,recfm=vb,lrecl=512,blksize=23440");
  9895.  if (!ftpfp) {
  9896.    perror(tempdsn);
  9897.    fprintf(stderr,
  9898.     "GOPHER: Can't open temporary file for remote FTP request\n");
  9899.    return NULL;
  9900.  }
  9901.  
  9902.  return ftpfp;
  9903.  
  9904. }
  9905.  
  9906. /*=================================================================*/
  9907.  
  9908. static Bool
  9909. authorized_file(struct recvstruct *R)
  9910. {
  9911.  char    *cp;
  9912.  FILE    *afp;
  9913.  int      n;
  9914.  int      hostcount;
  9915.  Bool     rc;
  9916.  char     filetest[RBUFSIZE];
  9917.  char     accline [RBUFSIZE];
  9918.  char     accfile [RBUFSIZE];
  9919.  char     acchost [RBUFSIZE];
  9920.  
  9921.  /* If non-socket interface, bypass the authorization check. */
  9922.  
  9923.  if (R->outfp) return TRUE;
  9924.  
  9925.  /* Check that the server is allowed to return data from the file
  9926.   * specified in R->fileptr.  Note that this could be the name of
  9927.   * an exec.  The name will be (dataset), EXEC:execname, or DD:file
  9928.   * - we look at only the first part, whitespace-delimited.
  9929.   * Entries in the file authorization table look as above.
  9930.   */
  9931.  
  9932.  rc = FALSE;
  9933.  filetest[0] = '\0';
  9934.  sscanf(R->fileptr,"%s",filetest);
  9935.  
  9936.  /* Read authorization file. */
  9937.  
  9938.  afp = fopen(ACCESS_TABLE,"r");
  9939.  if (!afp) {
  9940.    perror(ACCESS_TABLE);
  9941.    fflush(stderr);
  9942.    return FALSE;
  9943.  }
  9944.  
  9945.  for (;;) {
  9946.    fgets(accline, sizeof(accline), afp);
  9947.    if (ferror(afp)) {
  9948.      fprintf(stderr,"Error reading access table %s\n",ACCESS_TABLE);
  9949.      fflush(stderr);
  9950.      break;
  9951.    }
  9952.    if (feof(afp)) break;
  9953.    /* format of line is: filename machine(s) */
  9954.    uppercase_in_place(accline);
  9955.    cp = accline;                      /* Start scan pointer         */
  9956.    *accfile = '\0';                   /* Clear access file name     */
  9957.    sscanf(cp,"%s %n",accfile,&n);     /* Get file name, bump scan   */
  9958.    if (!strcmp(filetest,accfile)) {   /* If file name matches       */
  9959.      hostcount = 0;                   /* Clear access host count    */
  9960.      for (;;) {                       /* Loop over access host ids  */
  9961.        cp += n;                       /* Bump to next word in file  */
  9962.        *acchost = '\0';               /* Clear word before scanf    */
  9963.        sscanf(cp,"%s %n",acchost,&n); /* Get next word, bump scan   */
  9964.        if (!*acchost) break;          /* exit loop if no more hosts */
  9965.        hostcount++;                   /* increment access host count*/
  9966.        if (!strcmp(R->hostname,acchost)
  9967.         || !strcmp(R->hosttest,acchost)) { /* if hostname matches */
  9968.          rc = TRUE;                        /* access is allowed   */
  9969.          break;
  9970.        }
  9971.      }
  9972.      if (!rc) {                       /* If no matching host found  */
  9973.        if (hostcount == 0) rc = TRUE; /* if no access hosts, say OK */
  9974.      }
  9975.      if (rc) break;                   /* if access OK, finished     */
  9976.  
  9977.      /* If access is not permitted, we keep checking because
  9978.       * there may be more than one entry in the access table
  9979.       * for this file, so that many host names can be given.
  9980.       */
  9981.  
  9982.    }
  9983.  }
  9984.  
  9985.  (void)fclose(afp);
  9986.  
  9987.  if (!rc) {
  9988.    fprintf(stderr,"Not authorized from %s: '%s'\n",
  9989.                   R->hosttest, filetest);
  9990.  }
  9991.  
  9992.  fflush(stderr);
  9993.  
  9994.  return rc;
  9995. }
  9996.  
  9997. /*=================================================================*/
  9998.  
  9999. /*******************************************************************/
  10000. /*            This routine determines what type of gopher file     */
  10001. /*            we've opened.  We'll return the file type to the     */
  10002. /*            caller.                                              */
  10003. /*                                                                 */
  10004. /*            INPUT:   ident   pointer to first line of file       */
  10005. /*                                                                 */
  10006. /*            OUTPUT:   MENU   file type is a menu                 */
  10007. /*                      FILE   file type is a file                 */
  10008. /*                      INDEX  file type is an INDEX (not done)    */
  10009. /*******************************************************************/
  10010.  
  10011. static char
  10012. getftype(char *ident)
  10013. {
  10014.  int   x;                              /* loop counter */
  10015.  char  buffer[RBUFSIZE];
  10016.  char *bufptr;
  10017.  
  10018.  /**********/
  10019.  /*   first, convert the string to upper case...   */
  10020.  /*********/
  10021.  strcpy(buffer,ident);
  10022.  bufptr = uppercase_and_trim_leading_space(buffer);
  10023.  
  10024.  /**********/
  10025.  /*   return the type of file.                     */
  10026.  /*********/
  10027.  
  10028.  if(strcmp(bufptr,MENUIDENT)==0) return(MENU);
  10029.  if(strcmp(bufptr,INDEXIDENT)==0) return(INDEX);
  10030.  
  10031.  /**********/
  10032.  /*   don't know, so assume it's a "file" file...    */
  10033.  /*********/
  10034.  
  10035.  return(GFILE);
  10036.  
  10037. }
  10038.  
  10039. /*=================================================================*/
  10040.  
  10041. /*******************************************************************/
  10042. /*            This routine figures out what type of parm line      */
  10043. /*            the current line is.  We'll return the token         */
  10044. /*            type to the caller.                                  */
  10045. /*                                                                 */
  10046. /*            INPUT:   buffer  pointer to first line of file       */
  10047. /*                       (Note: string must be null terminated!    */
  10048. /*            OUTPUT:   Type of token.  (See in include file...)   */
  10049. /*******************************************************************/
  10050.  
  10051. static int
  10052. menukeywd(char  *buffer,
  10053.           char  *token,
  10054.           char  *operand)
  10055. {
  10056.  int             x;                              /* loop counter */
  10057.  char           *tokval;
  10058.  char           *oprval;
  10059.  char           *tokptr;
  10060.  char            tokstr[256];
  10061.  
  10062.  strcpy(tokstr,buffer);
  10063.  tokval=strtok(tokstr,"=");
  10064.  oprval=strtok(NULL,"");
  10065.  strcpy(token,tokval);
  10066.  strcpy(operand,oprval);
  10067.  tokptr = uppercase_and_trim_leading_space(token);
  10068.  
  10069.  /*********/
  10070.  /*  now look at the tokens to see if we have a weener... */
  10071.  /*********/
  10072.  
  10073.  if(strcmp(tokptr,TOKTYPE)==0) return(TYPETOK);
  10074.  if(strcmp(tokptr,TOKNAME)==0) return(NAMETOK);
  10075.  if(strcmp(tokptr,TOKPATH)==0) return(PATHTOK);
  10076.  if(strcmp(tokptr,TOKHOST)==0) return(HOSTTOK);
  10077.  if(strcmp(tokptr,TOKPORT)==0) return(PORTTOK);
  10078.  if(strcmp(tokptr,TOKEND)==0) return(ENDTOK);
  10079.  
  10080.  /* for back compatibility with the old MVS GOPHER server */
  10081.  
  10082.  if(strcmp(tokptr,TOKDISPLAY)==0) return(DISPLAYTOK);
  10083.  if(strcmp(tokptr,TOKSELECT)==0) return(SELECTTOK);
  10084.  
  10085.  return(COMMENTTOK);
  10086.  
  10087. }
  10088.  
  10089. /*=================================================================*/
  10090.  
  10091. /*******************************************************************/
  10092. /*       This routine reads a line from the specified file.        */
  10093. /*       if a read error occurs, an error message is printed and   */
  10094. /*       FALSE is returned.                                        */
  10095. /*                                                                 */
  10096. /*       INPUT   buffer      pointer to buffer to place line       */
  10097. /*               readfile    file structure to read from           */
  10098. /*                                                                 */
  10099. /*       OUTPUT  buffer      line that was read from the file      */
  10100. /*               TRUE        read worked ok                        */
  10101. /*               FALSE       read failed!                          */
  10102. /*******************************************************************/
  10103.  
  10104. static Bool
  10105. readaline(struct recvstruct *R)
  10106. {
  10107.  
  10108.  memset(R->buffer,0,RBUFSIZE);
  10109.  fread(R->buffer,RBUFSIZE,1,R->readfile);
  10110.  if (ferror(R->readfile)) {
  10111.    /* perror("FREAD"); */
  10112.    fprintf(stderr,"GGSTASK: Error reading file\n");
  10113.    return(FALSE);
  10114.  }
  10115.  trim_trailing_space(R->buffer); /* Remove trailing whitespace */
  10116.  return(TRUE);
  10117. }
  10118.  
  10119. /*=================================================================*/
  10120.  
  10121. /*******************************************************************/
  10122. /*   This routine sends a file to the calling client.              */
  10123. /*   It assumes the file is a text formatted file.                 */
  10124. /*   INPUT:   buffer    pointer to the already read line...        */
  10125. /*            readfile  file we're going to read from..            */
  10126. /*            maxlen    size of the buffer.                        */
  10127. /*            sockfd    socket descriptor for client.              */
  10128. /*                                                                 */
  10129. /*   OUTPUT:   send the file to the client                         */
  10130. /*******************************************************************/
  10131. static void
  10132. sendafile(struct recvstruct *R)
  10133. {
  10134.  int            x;
  10135.  char          *moveit;
  10136.  
  10137.  /*******/
  10138.  /*   send the first line (cause we already read it) */
  10139.  /*******/
  10140.  
  10141.  if (!GGMouts(R,R->buffer)) return;
  10142.  
  10143.  /*******/
  10144.  /*   get the rest of the lines of the file and send them... */
  10145.  /*******/
  10146.  
  10147.  for (;;) {
  10148.    if (!readaline(R)) {
  10149.      (void)GGMouts(R,"<<<*** I/O ERROR ON MVS FILE ***>>>");
  10150.      return;
  10151.    }
  10152.    if (feof(R->readfile)) break;
  10153.    if (!GGMouts(R,R->buffer)) return;
  10154.  }
  10155. }
  10156.  
  10157. /*=================================================================*/
  10158.  
  10159. /*******************************************************************/
  10160. /*   This routine formats a menu file into gopher data & sends it  */
  10161. /*   to the client.                                                */
  10162. /*   INPUT:   buffer    pointer to the already read line...        */
  10163. /*            readfile  file we're going to read from..            */
  10164. /*            maxlen    size of the buffer.                        */
  10165. /*            sockfd    socket descriptor for client               */
  10166. /*                                                                 */
  10167. /*   OUTPUT:   send the menu to the client                         */
  10168. /*******************************************************************/
  10169.  
  10170. #define MENU_STUFF_SIZE GOPHER_DESC_LENGTH + \
  10171.                         GOPHER_PATH_LENGTH + \
  10172.                         GOPHER_HOST_LENGTH + 20
  10173.  
  10174. static void
  10175. sendamenu(struct recvstruct *R)
  10176. {
  10177.  char           *moveit;
  10178.  char           *operptr;
  10179.  char           *typeoftype;             /*pointer for strtok   */
  10180.  char           *cp;
  10181.  int             kindotoken;
  10182.  int             x;                         /* loop counter */
  10183.  char            token   [133];
  10184.  char            operand [133];
  10185.  char            outbuf  [MENU_STUFF_SIZE];
  10186.  struct menuitem menu;
  10187.  
  10188.  memset(&menu,0,sizeof menu );
  10189.  for (;;) {
  10190.    if (!readaline(R)) break;
  10191.    if (feof(R->readfile)) break;
  10192.    if (!*R->buffer) continue;
  10193.    kindotoken = menukeywd(R->buffer,token,operand);
  10194.    switch(kindotoken) {
  10195.      case TYPETOK:
  10196.           operptr = uppercase_and_trim_leading_space(operand);
  10197.           typeoftype = strtok(operptr," ");
  10198.           if (strlen(typeoftype) == 1)      menu.type = *typeoftype;
  10199.           else
  10200.           if (EQUAL(typeoftype,TYPEFILE))   menu.type = GFILE;
  10201.           else
  10202.           if (EQUAL(typeoftype,TYPEMENU))   menu.type = MENU;
  10203.           else
  10204.           if (EQUAL(typeoftype,TYPEINDEX))  menu.type = INDEX;
  10205.           else
  10206.           if (EQUAL(typeoftype,TYPETELNET)) menu.type = TELNET;
  10207.           else
  10208.           if (EQUAL(typeoftype,TYPETN3270)) menu.type = TN3270;
  10209.           else
  10210.           if (EQUAL(typeoftype,TYPEWHOIS))  menu.type = WHOIS;
  10211.           else                              menu.type = ERROR;
  10212.           break;
  10213.      case NAMETOK:
  10214.      case DISPLAYTOK:
  10215.           strncpy(menu.desc,     operptr, sizeof(menu.desc));
  10216.           break;
  10217.      case PATHTOK:
  10218.      case SELECTTOK:
  10219.           strncpy(menu.select,   operptr, sizeof(menu.select));
  10220.           break;
  10221.      case HOSTTOK:
  10222.           if (EQUAL(operptr,IDENT_HOST_FROB)) {  /* HOST=+  */
  10223.             if (insure_my_name(R)) {
  10224.               strncpy(menu.hostname, R->myname, sizeof(menu.hostname));
  10225.             }
  10226.           }
  10227.           else {
  10228.             strncpy(menu.hostname, operptr, sizeof(menu.hostname));
  10229.           }
  10230.           break;
  10231.      case PORTTOK:
  10232.           if (EQUAL(operptr,IDENT_HOST_FROB)) {  /* PORT=+  */
  10233.             menu.port = R->myport;
  10234.           }
  10235.           else {
  10236.             menu.port=atoi(operptr);
  10237.           }
  10238.           break;
  10239.      case ENDTOK:
  10240.           if (menu.port == 0) {
  10241.             switch (menu.type) {
  10242.               case TELNET: break;
  10243.               case TN3270: break;
  10244.               default:     menu.port = GOPHER_PORT_NUMBER; break;
  10245.             }
  10246.           }
  10247.           /* If host is local and path is in the form "(member)",
  10248.            * and current dsname is a PDS, then use same PDS:
  10249.            * i.e. turn PATH=(FOOBAR) into PATH=AA.BB.CC(FOOBAR)
  10250.            */
  10251.           if (*R->myname
  10252.            && EQUAL(menu.hostname,R->myname)
  10253.            && *menu.select == '('        /* ) */
  10254.            && (cp = strchr(R->dsname,'(' /* ) */ ))) {
  10255.             memcpy(outbuf, R->dsname, (cp-R->dsname));
  10256.             strcpy(outbuf+(cp-R->dsname), menu.select);
  10257.             strncpy(menu.select, outbuf, sizeof(menu.select));
  10258.           }
  10259.           if (*menu.desc && *menu.hostname) {
  10260.             sprintf(outbuf,"%c%s\t%s\t%s\t%d",
  10261.                            menu.type,menu.desc,
  10262.                            menu.select,menu.hostname,menu.port);
  10263.             if (!GGMouts(R,outbuf)) return;
  10264.           }
  10265.           fflush(stdout);
  10266.           memset(&menu,0,sizeof menu );
  10267.           break;
  10268.      default:
  10269.           break;
  10270.        }
  10271.    }
  10272. }
  10273.  
  10274. /*=================================================================*/
  10275.  
  10276. static Bool
  10277. get_directory(struct recvstruct *R)
  10278. {
  10279.  FILE              *dirfile;
  10280.  int                i;
  10281.  short              block_count;
  10282.  short              bump_amount;
  10283.  Bool               reject;
  10284.  Bool               no_more;
  10285.  char              *cp;
  10286.  char              *mp;
  10287.  char               dirblk  [256];
  10288.  char               pdsspec [256];
  10289.  char               entry   [256];
  10290.  
  10291.  /* The local path name is required for this function. */
  10292.  
  10293.  if (!insure_my_name(R)) return FALSE;
  10294.  
  10295.  if ((dirfile=fopen(R->buffer,"rb,recfm=u,lrecl=256")) == NULL) {
  10296.    perror(R->buffer);
  10297.    printf("Can't open PDS directory:%s\n",R->dsname);
  10298.    gbarf(R,"the GOPHER server can't open the directory");
  10299.    return(FALSE);
  10300.  }
  10301.  
  10302.  while (!feof(dirfile)) {
  10303.  
  10304.    no_more = FALSE;
  10305.  
  10306.    do {
  10307.      memset(dirblk,0x00,256);
  10308.      fread(dirblk,256,1,dirfile);
  10309.      if (feof(dirfile)) break;
  10310.      if (ferror(dirfile)) {
  10311.        printf("Can't read PDS directory:%s\n", R->fileptr);
  10312.        gbarf(R,"the GOPHER server can't read the directory");
  10313.        fclose(dirfile);
  10314.        return FALSE;
  10315.      }
  10316.      mp = dirblk;
  10317.      block_count = *(short *)mp - 2;   /* # bytes in dir block */
  10318.      mp += 2;                        /* addr of dir block data */
  10319.      while (block_count > 0) {
  10320.        if (memcmp(mp,"\xff\xff\xff\xff\xff\xff\xff\xff",8)==0) break;
  10321.        reject = FALSE;
  10322.        /*
  10323.         * Uncomment this if you want to skip aliases.
  10324.         * It is recommended that you let aliases through, since
  10325.         * they often have better names (e.g. TSO HELP files)
  10326.         *
  10327.         * if ((mp[11] & 0x80) != 0) {
  10328.         *   fprintf(stderr,"Skipping alias:  %-8.8s\n",mp);
  10329.         *   reject = TRUE;
  10330.         * }
  10331.         */
  10332.        if (!reject) {
  10333.          strcpy(pdsspec, R->dsname);
  10334.          cp = strchr(pdsspec, '\0');
  10335.          *(cp++) = '(';
  10336.          for (i = 0; i < 8 && mp[i] != ' '; cp++, i++) *cp = mp[i];
  10337.          *(cp++) = ')';
  10338.          *cp = '\0';
  10339.          sprintf(entry,"0%8.8s\t%s\t%s\t%d",
  10340.                        mp, pdsspec, R->myname, SERV_TCP_PORT);
  10341.          (void)GGMouts(R,entry);
  10342.        }
  10343.        bump_amount = 12 + ((mp[11] & 0x1f) * 2);
  10344.        mp += bump_amount;
  10345.        block_count -= bump_amount;
  10346.      }
  10347.    } while(!no_more);
  10348.  
  10349.  }
  10350.  
  10351.  fclose(dirfile);
  10352.  return TRUE;
  10353. }
  10354.  
  10355. /*=================================================================*/
  10356.  
  10357. static Bool
  10358. get_flat_file(struct recvstruct *R)
  10359. {
  10360.  int                x;            /* loop counter*/
  10361.  int                numread;      /* number of items read... */
  10362.  char               filetype;     /* type of file we're dealing with*/
  10363.  
  10364.  if ((R->readfile=fopen(R->buffer,"rb,type=record")) == NULL) {
  10365.    perror(R->buffer);
  10366.    printf("INVALID! requested:%s\n",R->fileptr);
  10367.    gbarf(R,"the GOPHER server couldn't open the file");
  10368.    return(FALSE);
  10369.  }
  10370.  
  10371.  /************/
  10372.  /*  get the first line and see what type of file we've got.      */
  10373.  /************/
  10374.  
  10375.  if (readaline(R) && !feof(R->readfile)) {
  10376.  
  10377.    filetype=getftype(R->buffer);
  10378.  
  10379.   /************/
  10380.   /*  Now let's go do whatever we need to for this file type.    */
  10381.   /************/
  10382.  
  10383.    switch(filetype) {
  10384.      case MENU:
  10385.                  sendamenu(R);
  10386.                  break;
  10387.      case GFILE:
  10388.      default:
  10389.                  sendafile(R);
  10390.                  break;
  10391.    }
  10392.  
  10393.  }
  10394.  
  10395.  if(fclose(R->readfile) < 0) {
  10396.    /* perror("PROCESS CLOSE"); */
  10397.    fprintf(stderr,"GGSTASK: Error closing file %s\n",R->fileptr);
  10398.    gbarf(R,"the GOPHER server couldn't close the file");
  10399.    return FALSE;
  10400.  }
  10401.  
  10402.  return TRUE;
  10403.  
  10404. }
  10405.  
  10406. /*=================================================================*/
  10407.  
  10408. #define PARAMETER   unsigned int
  10409. #define LASTPARM(X) ((unsigned int)(X) | 0x80000000)
  10410.  
  10411. static Bool
  10412. get_exec_data(struct recvstruct *R)
  10413. {
  10414.  char              *command;
  10415.  char              *commandargs;
  10416.  unsigned int       bitflags;
  10417.  int                rexxrc;
  10418.  int                irxexecrc;
  10419.  int                commandlength;
  10420.  int                scan_count;
  10421.  int                i;
  10422.  Bool               rc;
  10423.  int              (*irxexec)();
  10424.  FILE              *fp;
  10425.  char               exectest[RBUFSIZE];
  10426.  PARAMETER          parameter[11];
  10427.  struct {
  10428.                          /* repeat this block for each argument */
  10429.          char      *argstring_ptr;
  10430.          int        argstring_length;
  10431.                          /* end repeat this block for each argument */
  10432.          int        argstring_end;
  10433.         }           arguments;
  10434.  
  10435.  struct {
  10436.          char       acryn[8];       /* "IRXEXECB" */
  10437.          int        length;
  10438.          int        reserved1;
  10439.          char       member[8];
  10440.          char       ddname[8];
  10441.          char       subcom[8];
  10442.          char      *dsnptr;
  10443.          int        dsnlen;
  10444.         }           execblk;
  10445.  
  10446.   /*
  10447.    * Menu item should look like this:
  10448.    *
  10449.    * exec:rexxname any args
  10450.    *
  10451.    * The exec should write output to SYSTSPRT.  Normal TSO command
  10452.    * output will be captured by the SYSTSPRT allocation only if
  10453.    * the Gopher server is run as a batch job.
  10454.    *
  10455.    * If this was sent by the client with a type 7 or type w, then
  10456.    * additional args will appear at the end delimited by a space.
  10457.    */
  10458.  
  10459.  irxexec = NULL;
  10460.  rc = TRUE;
  10461.  scan_count = 0;
  10462.  
  10463.  if (R->wargptr) {
  10464.    commandlength = strlen(R->fileptr) + strlen(R->wargptr) + 4;
  10465.    command = (char *)malloc(commandlength);
  10466.    if (!command) {
  10467.      printf("Cannot allocate %d bytes of memory for exec\n",
  10468.             commandlength);
  10469.      gbarf(R,"the GOPHER server ran out of memory");
  10470.      return FALSE;
  10471.    }
  10472.    else sprintf(command,"%s %s",R->fileptr,R->wargptr);
  10473.  }
  10474.  else {
  10475.    commandlength = 0;
  10476.    command = R->fileptr;
  10477.  }
  10478.  
  10479.  *exectest = '\0';
  10480.  sscanf(command, "%s %n", exectest, &scan_count);
  10481.  if (strlen(exectest) > 8) {
  10482.    gbarf(R,"name of exec is too long");
  10483.    return FALSE;
  10484.  }
  10485.  commandargs = command + scan_count;
  10486.  
  10487.  if (rc) {
  10488.    irxexec = (int(*)())fetch("IRXEXEC");
  10489.    if (!irxexec) {
  10490.      printf("Cannot fetch IRXEXEC\n");
  10491.      rc = FALSE;
  10492.    }
  10493.  }
  10494.  
  10495.  /* Give the exec an empty SYSTSPRT file to write into.
  10496.   * Then when we read it we can see only what was added.
  10497.   * Since IRXEXEC doesn't close SYSTSPRT, we can't remove it
  10498.   * and reallocate it.
  10499.   */
  10500.  
  10501.  if (rc) {
  10502.    fp = fopen("DD:SYSTSPRT","w");
  10503.    if (!fp) {
  10504.      perror("DD:SYSTSPRT");
  10505.      printf("Cannot open SYSTSPRT to prepare for REXX exec\n");
  10506.      rc = FALSE;
  10507.    }
  10508.  
  10509.    /* Open for write + close = clear it out */
  10510.  
  10511.    else if (fclose(fp) < 0) {
  10512.      printf("Cannot close SYSTSPRT to prepare for REXX exec\n");
  10513.      rc = FALSE;
  10514.    }
  10515.  }
  10516.  
  10517.  /* Set up parameters for IRXEXEC:
  10518.   *
  10519.   * Param 1  -  address of EXECBLK
  10520.   * Param 2  -  address of arguments
  10521.   * Param 3  -  bitflags
  10522.   * Param 4  -  address of INSTBLK
  10523.   * Param 5  -  address of CPPL
  10524.   * Param 6  -  address of EVALBLOCK
  10525.   * Param 7  -  address of 8-byte work area
  10526.   * Param 8  -  address of user field
  10527.   * Param 9  -  address of environment block
  10528.   * Param 10 -  return code
  10529.   *
  10530.   */
  10531.  
  10532.  if (rc) {
  10533.  
  10534.    /* set up exec block */
  10535.  
  10536.    memset (&execblk, 0, sizeof(execblk));
  10537.    execblk.length = sizeof(execblk);
  10538.    memcpy (execblk.acryn, "IRXEXECB", 8);
  10539.    strncpy(execblk.member,exectest,8);
  10540.    for (i=0;i<8;i++) {
  10541.      if (execblk.member[i] == '\0')
  10542.          execblk.member[i] = ' ';
  10543.    }
  10544.    /* We may have just clobbered this, so do this after... */
  10545.  
  10546.    memcpy (execblk.ddname, REXX_EXEC_LIBRARY_DDNAME, 8);
  10547.    memcpy (execblk.subcom, REXX_EXEC_SUBCOM,     8);
  10548.  
  10549.    /* set up arguments  */
  10550.  
  10551.    arguments.argstring_ptr    = commandargs;
  10552.    arguments.argstring_length = strlen(commandargs);
  10553.    arguments.argstring_end    = 0xffffffff;
  10554.  
  10555.    /* Invoke the rexx exec */
  10556.  
  10557.    if (!R->outfp) printf("Executing:%s\n", command);
  10558.  
  10559. #define INVOKE_EXEC_AS_COMMAND            (unsigned int)0x80000000
  10560. #define INVOKE_EXEC_AS_EXTERNAL_FUNCTION  (unsigned int)0x40000000
  10561. #define INVOKE_EXEC_AS_SUBROUTINE         (unsigned int)0x20000000
  10562. #define RETURN_EXTENDED_RETURN_CODES      (unsigned int)0x10000000
  10563.  
  10564.    rexxrc = 0;
  10565.    bitflags = (unsigned int)(INVOKE_EXEC_AS_COMMAND +
  10566.                              RETURN_EXTENDED_RETURN_CODES);
  10567.  
  10568.    parameter[ 1] =   (PARAMETER)&execblk;
  10569.    parameter[ 2] =   (PARAMETER)&arguments;
  10570.    parameter[ 3] =   (PARAMETER)bitflags;
  10571.    parameter[ 4] =   (PARAMETER)NULL;  /* no INSTBLK */
  10572.    parameter[ 5] =   (PARAMETER)NULL;  /* no CPPL    */
  10573.    parameter[ 6] =   (PARAMETER)NULL;  /* no eval block */
  10574.    parameter[ 7] =   (PARAMETER)NULL;  /* no work area */
  10575.    parameter[ 8] =   (PARAMETER)NULL;  /* no user field, last parm */
  10576.    parameter[ 9] =   (PARAMETER)NULL;  /* no environment block */
  10577.    parameter[10] =   (PARAMETER)0;     /* return code */
  10578.  
  10579.    irxexecrc = (*irxexec) (
  10580.                            ¶meter[1],
  10581.                            ¶meter[2],
  10582.                            ¶meter[3],
  10583.                            ¶meter[4],
  10584.                            ¶meter[5],
  10585.                            ¶meter[6],
  10586.                            ¶meter[7],
  10587.                            LASTPARM(¶meter[8]), /* old REXX */
  10588.                            ¶meter[9],
  10589.                            LASTPARM(¶meter[10]) /* new REXX */
  10590.                           );
  10591.  
  10592.    if (irxexecrc != 0) {
  10593.      fprintf(stderr,"Return code from IRXEXEC is %d\n", irxexecrc);
  10594.      gbarf(R,"the Gopher server was unable to run the exec");
  10595.      rc = FALSE;
  10596.    }
  10597.    else {
  10598.  
  10599.      rexxrc = parameter[10];
  10600.  
  10601.      if (!R->outfp) printf("Return code from exec is %d\n", rexxrc);
  10602.  
  10603.      /* Read what the exec wrote. */
  10604.  
  10605.      strcpy(R->buffer,"DD:SYSTSPRT");
  10606.      R->fileptr = R->buffer;
  10607.      rc = get_flat_file(R);
  10608.  
  10609.    }
  10610.  
  10611.  }
  10612.  
  10613.  else {
  10614.      gbarf(R,"the GOPHER server had a problem with the exec");
  10615.  }
  10616.  
  10617.  if (irxexec) release((void (*)())irxexec);
  10618.  
  10619.  if (commandlength > 0) free(command);
  10620.  
  10621.  return rc;
  10622.  
  10623. }
  10624.  
  10625. /*=================================================================*/
  10626.  
  10627. static Bool
  10628. get_ftp_data(struct recvstruct *R,
  10629.              int                ftptype,
  10630.              OSTYPE             ftpos,
  10631.              char              *hackprefix
  10632.             )
  10633. {
  10634.   /*
  10635.    * FTP hack.  The syntax is:
  10636.    * ftp0:host:path
  10637.    * ftp0:host:user:path
  10638.    * ftp0:host:user:pass:path
  10639.    * ftp1:host
  10640.    * ftp1:host:path
  10641.    * ftp1:host:user:path
  10642.    * ftp1:host:user:pass:path
  10643.    *
  10644.    * ftpvm0:vmhost:disk/path
  10645.    * ftpvm1:vmhost:disk
  10646.    *
  10647.    * ftp0 means ftp a file.
  10648.    * ftp1 means ftp a directory.
  10649.    * Obviously, ftp0:host cannot exist, because that will always
  10650.    *            look for a remote FTP directory.
  10651.    *
  10652.    * If path is omitted, then path is remote ftp current directory
  10653.    * If user is omitted, defaults to "anonymous".
  10654.    * If pass is omitted, defaults to "gopher@localhost.domain.qual"
  10655.    *
  10656.    * The syntax is defined to let path always be the last item
  10657.    * just in case the path name contains a colon.
  10658.    *
  10659.    * For backward compatibility for a very short time, the form
  10660.    * ftp:host(other stuff) will be permitted.  When this is used,
  10661.    * due to the limitations of the Gopher protocol, the only way to
  10662.    * let the server know that a directory instead of a file is wanted
  10663.    * is to append "/" to the end of the path.
  10664.    *
  10665.    * And, of course, if the path is omitted then that's got to be a
  10666.    * directory request as well.
  10667.    *
  10668.    */
  10669.  char              *ftpword1;
  10670.  char              *ftpword2;
  10671.  char              *ftpword3;
  10672.  char              *ftpword4;
  10673.  char              *cp;
  10674.  struct Ftp        *F;
  10675.  Bool               rc;
  10676.  struct Ftp         ftp;
  10677.  char               tempout [L_tmpnam];
  10678.  char               temperr [L_tmpnam];
  10679.  
  10680.  rc       = FALSE;
  10681.  ftpword1 = R->fileptr;
  10682.  ftpword2 = "";
  10683.  ftpword3 = "";
  10684.  ftpword4 = "";
  10685.  
  10686.  F = &ftp;
  10687.  memset((char *)F,0,sizeof(*F));
  10688.  
  10689.  if (!insure_my_name(R)) return FALSE;
  10690.  
  10691.  cp = strchr(ftpword1,':');
  10692.  if (cp) {
  10693.    *cp = '\0';
  10694.    ftpword2 = cp + 1;
  10695.    cp = strchr(ftpword2,':');
  10696.    if (cp) {
  10697.      *cp = '\0';
  10698.      ftpword3 = cp + 1;
  10699.      cp = strchr(ftpword3,':');
  10700.      if (cp) {
  10701.        *cp = '\0';
  10702.        ftpword4 = cp + 1;
  10703.      }
  10704.    }
  10705.  }
  10706.  strncpy(F->host, ftpword1, sizeof(F->host));
  10707.  if (*ftpword2) {
  10708.    if (*ftpword3) {
  10709.      if (*ftpword4) {
  10710.        strncpy(F->user, ftpword2, sizeof(F->user));
  10711.        strncpy(F->pass, ftpword3, sizeof(F->pass));
  10712.        strncpy(F->path, ftpword4, sizeof(F->path));
  10713.      }
  10714.      else {
  10715.        strncpy(F->user, ftpword2, sizeof(F->user));
  10716.        strncpy(F->path, ftpword3, sizeof(F->path));
  10717.      }
  10718.    }
  10719.    else {
  10720.      strncpy(F->path, ftpword2, sizeof(F->path));
  10721.    }
  10722.  }
  10723.  
  10724.  /* Set defaults for path, user and pass if omitted.
  10725.   * Note that the password is set to gopher@site.  If the site is
  10726.   * the "local" frob, then set it to the domain name, minus the
  10727.   * initial dot that should be there if you configured your MVS
  10728.   * gopher properly.
  10729.   */
  10730.  
  10731.  if (!*F->path) strcpy(F->path,"/");
  10732.  if (!*F->user) strcpy(F->user,"anonymous");
  10733.  if (!*F->pass) {
  10734.    strcpy(F->pass,"gopher@");
  10735.    if (EQUAL(R->myname,LOCAL_HOST_FROB)) strcat(F->pass,R->mydomain+1);
  10736.    else                                  strcat(F->pass,R->myname);
  10737.  }
  10738.  
  10739.  F->os = ftpos;
  10740.  strcpy(F->ftphack, hackprefix);
  10741.  
  10742.  switch (ftptype) {
  10743.    case 0:  /* ftp a file */
  10744.             F->type = 0;
  10745.             break;
  10746.    case 1:  /* ftp a directory */
  10747.             F->type = 1;
  10748.             break;
  10749.    default: /* compatibility mode */
  10750.             cp = F->path + strlen(F->path) - 1;
  10751.             if (*cp == '/') {
  10752.               *cp = '\0';
  10753.               F->type = 1;     /* directory */
  10754.             }
  10755.             else F->type = 0;  /* file */
  10756.             break;
  10757.  }
  10758.  
  10759.  /* Create temporary files for FTP output. */
  10760.  
  10761.  F->outfp = create_temporary_file(R,tempout);
  10762.  F->errfp = create_temporary_file(R,temperr);
  10763.  
  10764.  if (!F->outfp || !F->errfp) {
  10765.    gbarf(R,"the GOPHER server couldn't service the remote FTP request");
  10766.    return FALSE;
  10767.  }
  10768.  
  10769.  rc = GGMftp(R,F);
  10770.  
  10771.  fflush(F->outfp);
  10772.  fflush(F->errfp);
  10773.  
  10774.  CLOSETEMP(F->outfp);
  10775.  CLOSETEMP(F->errfp);
  10776.  
  10777.  if (rc) strcpy(R->buffer, tempout);
  10778.  else    strcpy(R->buffer, temperr);
  10779.  
  10780.  rc = get_flat_file(R);
  10781.  
  10782.  REMOVETEMP(tempout);
  10783.  REMOVETEMP(temperr);
  10784.  
  10785.  return rc;
  10786.  
  10787. }
  10788.  
  10789. /*=================================================================*/
  10790.  
  10791. /*******************************************************************/
  10792. /*   This routine Processes the file the user requested.           */
  10793. /*   If it's a menu, we'll form a menu line, if it's a             */
  10794. /*   file, we'll just send it as is.                               */
  10795. /*                                                                 */
  10796. /*   INPUT:   filename  pointer to the file name to open           */
  10797. /*            sockfd    socket descriptor for the client           */
  10798. /*                                                                 */
  10799. /*   OUTPUT:   print "gopher" lines.                               */
  10800. /*             TRUE  - file printed ok.                            */
  10801. /*             FALSE - Error reading or writing                    */
  10802. /*******************************************************************/
  10803.  
  10804. Bool
  10805. GGMproc(struct recvstruct *R)
  10806. {
  10807.  int                x;            /* loop counter*/
  10808.  int                numread;      /* number of items read... */
  10809.  int                hacksize;     /* length of hack prefix before : */
  10810.  Bool               rc;           /* return value */
  10811.  enum data_set_type dstype;       /* SEQ, PDS or UNK */
  10812.  char              *p;
  10813.  char              *q;
  10814.  char              *tabptr;
  10815.  char              *colonptr;
  10816.  char               ddname    [  9];
  10817.  char               hackprefix[ 17];
  10818.  
  10819.  *ddname     = '\0';
  10820.  *hackprefix = '\0';
  10821.  
  10822.  /************/
  10823.  /*  First, strip off any "bad" characters from the arguments. */
  10824.  /************/
  10825.  
  10826.  /*
  10827.   * Break the argument up into one or two pieces delimited by tab.
  10828.   */
  10829.  
  10830.  R->fileptr = R->buffer;        /* filename passed in buffer */
  10831.  
  10832.  tabptr = strchr(R->fileptr,'\t');
  10833.  if (tabptr) {
  10834.    *tabptr = '\0';
  10835.    R->fileptr = trim_leading_and_trailing_space(R->fileptr);
  10836.    R->wargptr = trim_leading_and_trailing_space(tabptr+1);
  10837.  }
  10838.  else {
  10839.    R->fileptr = trim_leading_and_trailing_space(R->fileptr);
  10840.    R->wargptr = NULL;
  10841.  }
  10842.  
  10843.  if (!*R->fileptr) {
  10844.    R->fileptr = DEFAULT_DIRECTORY;
  10845.  }
  10846.  
  10847.  /* If first character is numeric, assume it's a gopher type.
  10848.   * Later we will actually support different types...
  10849.   */
  10850.  
  10851.  switch (*R->fileptr) {
  10852.    case '0':
  10853.    case '1':
  10854.    case '2':
  10855.    case '3':
  10856.    case '4':
  10857.    case '5':
  10858.    case '6':
  10859.    case '7':
  10860.    case '8':
  10861.    case '9':  R->fileptr++; break;
  10862.    default:                 break;
  10863.  }
  10864.  
  10865.  if (!R->outfp) printf("%s: requested:%s;\n",R->hostname,R->fileptr);
  10866.  
  10867.  /*
  10868.   * Process special hacks here.
  10869.   *
  10870.   * For example, if the file name begins with "exec:", then
  10871.   * execute the specified REXX exec.
  10872.   *
  10873.   * Hackless names are processed as files.  "dd:" is not a
  10874.   * special hack but the normal C/370 DDname reference.
  10875.   *
  10876.   */
  10877.  
  10878.  colonptr = strchr(R->fileptr,':');
  10879.  if (colonptr) {
  10880.    hacksize = colonptr - R->fileptr;
  10881.    if (hacksize > 0 && hacksize < sizeof(hackprefix)) {
  10882.      for (p = hackprefix, q = R->fileptr;
  10883.           hacksize > 0;
  10884.           p++, q++, hacksize--) *p = toupper(*q);
  10885.      *p = '\0';
  10886.    }
  10887.  }
  10888.  
  10889.  if (EQUAL(hackprefix,"EXEC")) {
  10890.   /*
  10891.    * REXX exec, which must reside in SYSEXEC DD.
  10892.    */
  10893.    if (!authorized_file(R)) {
  10894.      gbarf(R,"the GOPHER server won't run the exec for you");
  10895.      rc = FALSE;
  10896.    }
  10897.    else {
  10898.      R->fileptr = colonptr + 1;  /* point to exec itself */
  10899.      rc = get_exec_data(R);
  10900.    }
  10901.  }
  10902.  else
  10903.   /*
  10904.    * Note for the FTP options
  10905.    *       No authorized-file check is done, because we assume that
  10906.    *       any file available via anonymous ftp is wide open to the
  10907.    *       world to begin with.  Besides, we can't possibly specify
  10908.    *       every remote file in the entire universe, now, can we?
  10909.    */
  10910.  if (EQUAL(hackprefix,"FTP")) { /* we're gonna get rid of this */
  10911.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  10912.    rc = get_ftp_data(R,-1,DEFAULT_OS,"FTP");
  10913.  }
  10914.  else
  10915.  if (EQUAL(hackprefix,"FTP0")) { /* ftp a file */
  10916.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  10917.    rc = get_ftp_data(R,0,DEFAULT_OS,"FTP");
  10918.  }
  10919.  else
  10920.  if (EQUAL(hackprefix,"FTP1")) { /* ftp a direectory */
  10921.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  10922.    rc = get_ftp_data(R,1,DEFAULT_OS,"FTP");
  10923.  }
  10924.  else
  10925.  if (EQUAL(hackprefix,"FTPVM0")) { /* ftp a file */
  10926.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  10927.    rc = get_ftp_data(R,0,VM_OS,"FTPVM");
  10928.  }
  10929.  else
  10930.  if (EQUAL(hackprefix,"FTPVM1")) { /* ftp a direectory */
  10931.    R->fileptr = colonptr + 1;  /* point to ftp locator */
  10932.    rc = get_ftp_data(R,1,VM_OS,"FTPVM");
  10933.  }
  10934.  else
  10935.  if (EQUAL(hackprefix,"DD")) {
  10936.   /*
  10937.    * C/370 style ddname.  Assume sequential file - cannot be a PDS
  10938.    * because I don't feel like trying to determine that right now.
  10939.    */
  10940.    if (!authorized_file(R)) {
  10941.      gbarf(R,"the GOPHER server won't read the DD for you");
  10942.      rc = FALSE;
  10943.    }
  10944.    else {
  10945.      strcpy(R->buffer,R->fileptr); /* still points to "DD:xxxxxxxx" */
  10946.      strcpy(R->dsname,R->fileptr); /* needed for PATH=(member) check */
  10947.      dstype = SEQ;
  10948.      rc = get_flat_file(R);
  10949.    }
  10950.  }
  10951.  else {
  10952.    /* Regular file name without ":" hack, or with invalid ":" hack.
  10953.     * Check to see that the file name is on our "official" list.
  10954.     */
  10955.    if (!authorized_file(R)) {
  10956.      gbarf(R,"the GOPHER server won't let you see the file");
  10957.      rc = FALSE;
  10958.    }
  10959.    else {
  10960.  
  10961.    /* Dynamically allocate data set and use generated ddname.
  10962.     * Note that we have to allocate the data set name to a ddname and
  10963.     * then open the ddname to prevent C/370 from barfing on otherwise
  10964.     * valid data set names like those with hyphens in them.  But this
  10965.     * also lets us determine if the data set is sequential or a PDS.
  10966.     */
  10967.      strcpy(R->dsname,R->fileptr);
  10968.      dstype = GGMalloc(R->dsname,ddname,UNK,0);
  10969.      sprintf(R->buffer,"DD:%s",ddname);
  10970.      switch (dstype) {
  10971.        case SEQ: rc = get_flat_file(R); break;
  10972.        case PDS: rc = get_directory(R); break;
  10973.        default:
  10974.                printf("INVALID! requested:%s\n",R->fileptr);
  10975.                gbarf(R,"the GOPHER server couldn't allocate the file");
  10976.                rc = FALSE;
  10977.      }
  10978.    }
  10979.  }
  10980.  
  10981.  GGMunalc(ddname);  /* free the ddname if set */
  10982.  
  10983.  if (!rc) {
  10984.    fflush(stdout);
  10985.    fflush(stderr);
  10986.  }
  10987.  
  10988.  return rc;
  10989.  
  10990. }
  10991.  
  10992. ./ ADD NAME=GGMSOCKT
  10993.  
  10994.  /********************************************************************/
  10995.  /*                                                                  */
  10996.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  10997.  /*                                                                  */
  10998.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  10999.  /*                                                                  */
  11000.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11001.  /* including the implied warranties of merchantability and fitness, */
  11002.  /* are expressly denied.                                            */
  11003.  /*                                                                  */
  11004.  /* Provided this copyright notice is included, this software may    */
  11005.  /* be freely distributed and not offered for sale.                  */
  11006.  /*                                                                  */
  11007.  /* Changes or modifications may be made and used only by the maker  */
  11008.  /* of same, and not further distributed.  Such modifications should */
  11009.  /* be mailed to the author for consideration for addition to the    */
  11010.  /* software and incorporation in subsequent releases.               */
  11011.  /*                                                                  */
  11012.  /********************************************************************/
  11013.  
  11014. #pragma  csect(code,  "GG@SOCKT")
  11015. #pragma  csect(static,"GG$SOCKT")
  11016. #include "gg.h"
  11017.  
  11018. /****** Output one data line for the server. *************************/
  11019.  
  11020. Bool
  11021. GGMsockt(gp,sp)
  11022. Rstruc ggcb        *gp;
  11023. Rstruc connection  *sp;
  11024. {
  11025.  int                gopher_bytes;
  11026.  int                writrc;
  11027.  char              *s_buf;
  11028.  Bool               procok;
  11029.  struct recvstruct *R;
  11030.  
  11031.  /* Before sending a request to the server, do a cleanup operation
  11032.   * to make sure that no more responses are coming from the server.
  11033.   * This is done by GGMservr here, but it is now done outside so that
  11034.   * the FTP gateway can call this routine without linkind it in.
  11035.   *
  11036.   *  GGMesrvr(gp,sp);           -- End server read --
  11037.   *
  11038.   */
  11039.  
  11040.  /* If local mode, call server subtask processor with command. */
  11041.  
  11042.  if (gp && (R=gp->recvp) && !sp->is_ftp) {
  11043.    if (!R->outfp) {
  11044.      CRIT1("Can't send data locally, non-socket not connected");
  11045.      return FALSE;
  11046.    }
  11047.    strncpy(R->buffer, gp->gopher_command, sizeof(R->buffer)-1);
  11048.    strcpy(R->myname, LOCAL_HOST_FROB);  /* used by PDS feature */
  11049.  
  11050.    /* allocate SYSTSPRT file, used by REXX EXEC interface */
  11051.  
  11052.    if (GGMtso(
  11053.      "ALLOC FI(SYSTSPRT) T SP(100 100) REL REU DEL"
  11054.      " RECFM(V B) LRECL(1024) BLKSIZE(32760)"
  11055.              ) != 0) {
  11056.      fprintf(stderr,
  11057.        "Warning: Cannot allocate temporary SYSTSPRT file.\n");
  11058.      fprintf(stderr,
  11059.        "         Some interfaces may not work properly.\n");
  11060.    }
  11061.  
  11062.    procok = GGMproc(R);
  11063.  
  11064.    /* free SYSTSPRT file, used by REXX EXEC interface */
  11065.  
  11066.    (void)GGMunalc("SYSTSPRT");
  11067.  
  11068.    /* Prepare to read from the beginning of the file */
  11069.  
  11070.    if (fseek(R->outfp, 0, SEEK_SET) != 0) {
  11071.      CRIT1("Can't reposition to start of local file");
  11072.      return FALSE;
  11073.    }
  11074.    return procok;
  11075.  }
  11076.  
  11077.  if (gp) {
  11078.    gopher_bytes = strlen(gp->gopher_command);
  11079.    memcpy(sp->client_buf,gp->gopher_command,gopher_bytes);
  11080.  }
  11081.  else {
  11082.    gopher_bytes = strlen(sp->client_buf);
  11083.  }
  11084.  
  11085.  sp->client_buf[gopher_bytes]   = CARRIAGE_RETURN;
  11086.  sp->client_buf[gopher_bytes+1] = LINE_FEED;
  11087.  
  11088.  if (!sp->is_ftp        &&
  11089.      sp->receiving_text &&
  11090.      gopher_bytes == 1  &&
  11091.      sp->client_buf[0] == '.') {
  11092.    sp->receiving_text = FALSE;
  11093.  }
  11094.  
  11095.  if (gp && gp->debug_mode)
  11096.     GGMdump(gp,"Writing to server",sp->client_buf,gopher_bytes+2);
  11097.  
  11098. #ifdef MVS
  11099.  EBCDIC_TO_ASCII(sp->client_buf,gopher_bytes+2);
  11100. #endif
  11101.  
  11102.  writrc = write(sp->ns, sp->client_buf, gopher_bytes+2);
  11103.  if (writrc < 0) {
  11104.    sp->connection_broken = TRUE;
  11105.    if (gp) {
  11106.      CRIT2("TCP/IP error: write() failed to send data to server %s.",
  11107.            gp->ggserver);
  11108.    }
  11109.    else {
  11110.      fprintf(stderr,
  11111.              "TCP/IP error: write() failed to send data to server %s.",
  11112.              sp->server_hostname);
  11113.    }
  11114.    return FALSE;
  11115.  }
  11116.  
  11117.  if (sp->is_ftp) return TRUE;
  11118.  
  11119.  /* Prepare server for read. */
  11120.  
  11121.  sp->server_has_something_pending = TRUE;
  11122.  sp->server_finished_replying     = FALSE;
  11123.  sp->sending_text                 = FALSE;
  11124.  sp->dont_read                    = FALSE;
  11125.  
  11126.  (void)GGMispf(gp,"CONTROL DISPLAY LOCK");
  11127.  (void)GGMispf(gp,"DISPLAY PANEL(GGMLSOCK)");
  11128.  
  11129.  return TRUE;
  11130. }
  11131.  
  11132. ./ ADD NAME=GGMSOPT
  11133.  
  11134.  /********************************************************************/
  11135.  /*                                                                  */
  11136.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  11137.  /*                                                                  */
  11138.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11139.  /*                                                                  */
  11140.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11141.  /* including the implied warranties of merchantability and fitness, */
  11142.  /* are expressly denied.                                            */
  11143.  /*                                                                  */
  11144.  /* Provided this copyright notice is included, this software may    */
  11145.  /* be freely distributed and not offered for sale.                  */
  11146.  /*                                                                  */
  11147.  /* Changes or modifications may be made and used only by the maker  */
  11148.  /* of same, and not further distributed.  Such modifications should */
  11149.  /* be mailed to the author for consideration for addition to the    */
  11150.  /* software and incorporation in subsequent releases.               */
  11151.  /*                                                                  */
  11152.  /********************************************************************/
  11153.  
  11154. #pragma  csect(code,  "GG@SOPT ")
  11155. #pragma  csect(static,"GG$SOPT ")
  11156. #include "gg.h"
  11157.  
  11158. #define BOOLOPTSET(A,B,C) \
  11159.    switch (A[0]) { \
  11160.      case  'n': \
  11161.      case  'N':   B = FALSE; break; \
  11162.      case  'y': \
  11163.      case  'Y':   B = TRUE; break; \
  11164.      case '\0': \
  11165.      default:     B = C; break; \
  11166.    }
  11167.  
  11168. /****** Set options that are stored in ISPF profile. *****************/
  11169.  
  11170. void
  11171. GGMsopt(gp,which)
  11172. Rstruc ggcb        *gp;
  11173. enum user_option    which;
  11174. {
  11175.  int                arrows;
  11176.  char               ggextpow[  4];
  11177.  char               ggextpap[  4];
  11178.  char               ggscroll[  4];
  11179.  char               ggcursor[  4];
  11180.  
  11181.  if (which == OPTION_ALL) {
  11182.    GGMispf(gp, "VGET (GGEXTPOW GGEXTPAP GGSCROLL GGCURSOR) PROFILE");
  11183.  }
  11184.  
  11185.  if (which == OPTION_ALL || which == OPTION_OTHER) {
  11186.  
  11187.    (void)GGMivget(gp,"GGEXTPOW ", ggextpow, sizeof(ggextpow));
  11188.    (void)GGMivget(gp,"GGEXTPAP ", ggextpap, sizeof(ggextpap));
  11189.  
  11190.    BOOLOPTSET(ggextpow, gp->warn_overwrite,              TRUE);
  11191.    BOOLOPTSET(ggextpap, gp->warn_append,                 TRUE);
  11192.  
  11193.  }
  11194.  
  11195.  if (which == OPTION_ALL || which == OPTION_VIEW) {
  11196.  
  11197.    (void)GGMivget(gp,"GGSCROLL ", ggscroll, sizeof(ggscroll));
  11198.    (void)GGMivget(gp,"GGCURSOR ", ggcursor, sizeof(ggcursor));
  11199.  
  11200.    BOOLOPTSET(ggscroll, gp->autoscroll, TRUE);
  11201.    BOOLOPTSET(ggcursor, gp->autocursor, FALSE);
  11202.  
  11203.  }
  11204.  
  11205.  return;
  11206. }
  11207.  
  11208. ./ ADD NAME=GGMTNET
  11209.  
  11210.  /********************************************************************/
  11211.  /*                                                                  */
  11212.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  11213.  /*                                                                  */
  11214.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11215.  /*                                                                  */
  11216.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11217.  /* including the implied warranties of merchantability and fitness, */
  11218.  /* are expressly denied.                                            */
  11219.  /*                                                                  */
  11220.  /* Provided this copyright notice is included, this software may    */
  11221.  /* be freely distributed and not offered for sale.                  */
  11222.  /*                                                                  */
  11223.  /* Changes or modifications may be made and used only by the maker  */
  11224.  /* of same, and not further distributed.  Such modifications should */
  11225.  /* be mailed to the author for consideration for addition to the    */
  11226.  /* software and incorporation in subsequent releases.               */
  11227.  /*                                                                  */
  11228.  /********************************************************************/
  11229.  
  11230. #pragma  csect(code,  "GG@TNET ")
  11231. #pragma  csect(static,"GG$TNET ")
  11232. #include "gg.h"
  11233.  
  11234. /* Additional code by Denis De La Roca <denis@mvs.oac.ucla.edu> */
  11235.  
  11236. /****** Gopher TELNET interface. *************************************/
  11237.  
  11238. Bool
  11239. GGMtnet(gp,ip,how)
  11240. Rstruc ggcb        *gp;
  11241. Rstruc gopherinfo  *ip;
  11242. GOHOW               how;
  11243. {
  11244.  int                tsorc;
  11245.  int                cnt          = 0;
  11246.  char              *userid       = NULL;
  11247.  char              *password     = NULL;
  11248.  char               tpath [128];
  11249.  char               tsocmd[256];
  11250.  char               tstuff[256];
  11251.  
  11252.  switch (how) {
  11253.    case AS_NORMAL: break;
  11254.    default:
  11255.                    ERR1("TELNET interface cannot be viewed as a file.");
  11256.                    return FALSE;
  11257.  }
  11258.  
  11259.  GGMispf(gp,"CONTROL DISPLAY LINE");
  11260.  
  11261.  /* Parse userid/password for Xtelnet's autologin */
  11262.  
  11263. #ifdef XTELNET_AUTOLOGIN
  11264.  
  11265.  if (EQUAL(gp->mytelnet, "XTELNET") && *ip->path) {
  11266.  
  11267.    strcpy(tpath, ip->path);
  11268.    userid = tpath;
  11269.    password = strchr(tpath, ',');
  11270.    if (password) {
  11271.      *password = '\0';
  11272.      password = strchr(password + 1, ':');
  11273.      if (password) {
  11274.        if (!memcmp(password - 7, "assword", 7)) password += 2;
  11275.        else                                     password = NULL;
  11276.      }
  11277.    }
  11278.    cnt += sprintf(tsocmd+cnt, "%s -l %s", gp->mytelnet, userid);
  11279.    if (password)
  11280.       cnt += sprintf(tsocmd+cnt, "/%s", password);
  11281.    cnt += sprintf(tsocmd+cnt, " %s", ip->host);
  11282.    if (ip->port > 0)
  11283.       cnt += sprintf(tsocmd+cnt, " %d", ip->port);
  11284.  }
  11285.  
  11286.  else { /* IBM's Telnet does not support autologin */
  11287.  
  11288. #endif
  11289.  
  11290.    /* Print note only if we have non-null path */
  11291.  
  11292.    if (*ip->path) {
  11293.      fprintf(stderr,"Note: Login as user: %s\n\n", ip->path);
  11294.    }
  11295.  
  11296.    if (ip->port==0) sprintf(tsocmd,"%s %s",gp->mytelnet,ip->host);
  11297.    else sprintf(tsocmd,"%s %s %d",gp->mytelnet,ip->host,ip->port);
  11298.  
  11299. #ifdef XTELNET_AUTOLOGIN
  11300.  
  11301.  }
  11302.  
  11303. #endif
  11304.  
  11305.  if ((tsorc = GGMtso(tsocmd)) != 0) {
  11306.    ERR3("Command \"%s\" returned code %d", tsocmd, tsorc);
  11307.  }
  11308.  
  11309.  GGMispf(gp,"CONTROL DISPLAY REFRESH");
  11310.  
  11311.  return TRUE;
  11312. }
  11313.  
  11314. ./ ADD NAME=GGMTSO
  11315.  
  11316.  /********************************************************************/
  11317.  /*                                                                  */
  11318.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  11319.  /*                                                                  */
  11320.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11321.  /*                                                                  */
  11322.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11323.  /* including the implied warranties of merchantability and fitness, */
  11324.  /* are expressly denied.                                            */
  11325.  /*                                                                  */
  11326.  /* Provided this copyright notice is included, this software may    */
  11327.  /* be freely distributed and not offered for sale.                  */
  11328.  /*                                                                  */
  11329.  /* Changes or modifications may be made and used only by the maker  */
  11330.  /* of same, and not further distributed.  Such modifications should */
  11331.  /* be mailed to the author for consideration for addition to the    */
  11332.  /* software and incorporation in subsequent releases.               */
  11333.  /*                                                                  */
  11334.  /********************************************************************/
  11335.  
  11336.  /********************************************************************/
  11337.  /*                                                                  */
  11338.  /* Thanks to Michael Van Norman for this code.                      */
  11339.  /*                                                                  */
  11340.  /********************************************************************/
  11341.  
  11342. #pragma  csect(code,  "GG@TSO  ")
  11343. #pragma  csect(static,"GG$TSO  ")
  11344. #include "gg.h"
  11345.  
  11346. #pragma linkage(ikjeftsr,OS)
  11347.  
  11348. #define _IKJEFTSR_FLAGS_AUTH        0x00000000
  11349. #define _IKJEFTSR_FLAGS_COMMAND     0x00000001
  11350. #define _IKJEFTSR_FLAGS_DUMP        0x00000100
  11351. #define _IKJEFTSR_FLAGS_NODUMP      0x00000000
  11352. #define _IKJEFTSR_FLAGS_PROGRAM     0x00000002
  11353. #define _IKJEFTSR_FLAGS_UNAUTH      0x00010000
  11354.  
  11355. /****** Issue TSO command. *******************************************/
  11356.  
  11357. int
  11358. GGMtso(command)
  11359. char        *command;
  11360. {
  11361.  int         flags         = _IKJEFTSR_FLAGS_COMMAND +
  11362.                              _IKJEFTSR_FLAGS_UNAUTH;
  11363.  int         commandLength = strlen(command);
  11364.  int         rc            = 0;
  11365.  int         returnCode    = 0;
  11366.  int         reasonCode    = 0;
  11367.  int         abendCode     = 0;
  11368.  
  11369.  static int (*ikjeftsr)() = NULL;
  11370.  
  11371.  if (!ikjeftsr) {
  11372.    int tsoEntryAddress;
  11373.  
  11374.    tsoEntryAddress = 0x00000010;    /* Address of CVT */
  11375.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  11376.    tsoEntryAddress += 0x9C;/*       /* Offset of TVT in CVT */
  11377.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  11378.    tsoEntryAddress += 0x10;/*       /* TSVTASF-TSVT (from IKJTSVT) */
  11379.    tsoEntryAddress = *(int *)(tsoEntryAddress);
  11380. #ifndef SASC
  11381.    ikjeftsr = (int (*)())(tsoEntryAddress);
  11382. #else
  11383.    ikjeftsr = (__ibmos int (*)())(tsoEntryAddress);
  11384. #endif
  11385.  }
  11386.  
  11387.  if (!ikjeftsr) {
  11388.    fprintf(stderr,
  11389.            "Cannot execute TSO commands, can't fetch IKJEFTSR.\n");
  11390.    return -2;
  11391.  }
  11392.  
  11393.  rc = (*ikjeftsr)(&flags, command, &commandLength,
  11394.                           &returnCode, &reasonCode,
  11395.                           (int *)((int)(&abendCode) | 0x80000000));
  11396.  
  11397.  if (rc != 0) {
  11398.    if (rc > 4) {
  11399.      fprintf(stderr,"Command failed:%s\n",command);
  11400.      if (rc == 20 && reasonCode == 40)
  11401.           fprintf(stderr,"Command was not found.\n");
  11402.      else fprintf(stderr,
  11403.              "rc=%d,returncode=%d,reasoncode=%d,abendcode=%8.8x\n",
  11404.              rc, returnCode, reasonCode, abendCode);
  11405.    }
  11406.    if (abendCode != 0) rc = -1;
  11407.    else rc = returnCode;
  11408.  }
  11409.  
  11410.  return rc;
  11411. }
  11412.  
  11413. ./ ADD NAME=GGMTYPE
  11414.  
  11415.  /********************************************************************/
  11416.  /*                                                                  */
  11417.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  11418.  /*                                                                  */
  11419.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11420.  /*                                                                  */
  11421.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11422.  /* including the implied warranties of merchantability and fitness, */
  11423.  /* are expressly denied.                                            */
  11424.  /*                                                                  */
  11425.  /* Provided this copyright notice is included, this software may    */
  11426.  /* be freely distributed and not offered for sale.                  */
  11427.  /*                                                                  */
  11428.  /* Changes or modifications may be made and used only by the maker  */
  11429.  /* of same, and not further distributed.  Such modifications should */
  11430.  /* be mailed to the author for consideration for addition to the    */
  11431.  /* software and incorporation in subsequent releases.               */
  11432.  /*                                                                  */
  11433.  /********************************************************************/
  11434.  
  11435. #pragma  csect(code,  "GG@TYPE ")
  11436. #pragma  csect(static,"GG$TYPE ")
  11437. #include "gg.h"
  11438.  
  11439. /*********************************************************************/
  11440.  
  11441. char *
  11442. GGMtype(gophertype t)
  11443. {
  11444.  
  11445.  switch (t) {
  11446.    case GOPHER_FILE:        return "File     ";
  11447.    case GOPHER_DIRECTORY:   return "Directory";
  11448.    case GOPHER_CSO:         return "Cso      ";
  11449.    case GOPHER_ERROR:       return "Error    ";
  11450.    case GOPHER_MAC_BINHEX:  return "Binhex   ";
  11451.    case GOPHER_DOS_BINARCH: return "Binarch  ";
  11452.    case GOPHER_UUENCODE:    return "Uuencode ";
  11453.    case GOPHER_WAIS:        return "Index    ";
  11454.    case GOPHER_TELNET:      return "Telnet   ";
  11455.    case GOPHER_TN3270:      return "TN3270   ";
  11456.    case GOPHER_BINARY:      return "Binary   ";
  11457.    case GOPHER_REDUNDANT:   return "Redundant";
  11458.    case GOPHER_WHOIS:       return "Whois    ";
  11459.    default:                 return "Unknown  ";
  11460.  }
  11461. }
  11462.  
  11463. ./ ADD NAME=GGMUNALC
  11464.  
  11465.  /********************************************************************/
  11466.  /*                                                                  */
  11467.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  11468.  /*                                                                  */
  11469.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11470.  /*                                                                  */
  11471.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11472.  /* including the implied warranties of merchantability and fitness, */
  11473.  /* are expressly denied.                                            */
  11474.  /*                                                                  */
  11475.  /* Provided this copyright notice is included, this software may    */
  11476.  /* be freely distributed and not offered for sale.                  */
  11477.  /*                                                                  */
  11478.  /* Changes or modifications may be made and used only by the maker  */
  11479.  /* of same, and not further distributed.  Such modifications should */
  11480.  /* be mailed to the author for consideration for addition to the    */
  11481.  /* software and incorporation in subsequent releases.               */
  11482.  /*                                                                  */
  11483.  /********************************************************************/
  11484.  
  11485. #pragma  csect(code,  "GG@UNALC")
  11486. #pragma  csect(static,"GG$UNALC")
  11487. #include "gg.h"
  11488.  
  11489. /****** Unallocate a data set. ***************************************/
  11490.  
  11491. Bool
  11492. GGMunalc(ddname)
  11493. char         *ddname;
  11494. {
  11495.  __S99parms   stuff99;   /* The manual has it wrong.  No "struct". */
  11496.  int          rc;
  11497.  char        *cp;
  11498.  TEXTUNIT    *tu [2];
  11499.  TEXTUNIT     tu_ddn;
  11500.  TEXTUNIT     tu_una;
  11501.  
  11502.  if (!ddname ||
  11503.      !*ddname) return TRUE;   /* if no ddname to free, do nothing */
  11504.  
  11505.  memset((char *)&stuff99,0,sizeof(__S99parms));
  11506.  
  11507.  stuff99.__S99RBLN   = 20;
  11508.  stuff99.__S99VERB   = S99VRBUN;
  11509.  stuff99.__S99FLAG1  = 0;
  11510.  stuff99.__S99ERROR  = 0;
  11511.  stuff99.__S99INFO   = 0;
  11512.  stuff99.__S99TXTPP  = tu;
  11513.  stuff99.__S99FLAG2  = 0;
  11514.  
  11515.  tu[0] = &tu_ddn;
  11516.  tu[1] = &tu_una;
  11517.  *(int *)&tu[1] |= 0x80000000;
  11518.  
  11519.  tu_ddn.key     = DUNDDNAM;
  11520.  tu_ddn.num     = 1;
  11521.  tu_ddn.ent.len = strlen(ddname);
  11522.  strcpy(tu_ddn.ent.prm,ddname);
  11523.  
  11524.  tu_una.key     = DUNUNALC;
  11525.  tu_una.num     = 0;
  11526.  
  11527.  for (cp=tu_ddn.ent.prm; *cp; cp++) *cp = toupper(*cp);
  11528.  
  11529.  rc = svc99(&stuff99);
  11530.  
  11531.  if (rc == 0) return TRUE;
  11532.  else if (stuff99.__S99ERROR == 0x0438) /* not freed, is not allocated*/
  11533.          return TRUE;
  11534.  else {
  11535.    GGMdfail(rc,&stuff99);
  11536.    return FALSE;
  11537.  }
  11538. }
  11539.  
  11540. ./ ADD NAME=GGMVIEW
  11541.  
  11542.  /********************************************************************/
  11543.  /*                                                                  */
  11544.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993    */
  11545.  /*                                                                  */
  11546.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  11547.  /*                                                                  */
  11548.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  11549.  /* including the implied warranties of merchantability and fitness, */
  11550.  /* are expressly denied.                                            */
  11551.  /*                                                                  */
  11552.  /* Provided this copyright notice is included, this software may    */
  11553.  /* be freely distributed and not offered for sale.                  */
  11554.  /*                                                                  */
  11555.  /* Changes or modifications may be made and used only by the maker  */
  11556.  /* of same, and not further distributed.  Such modifications should */
  11557.  /* be mailed to the author for consideration for addition to the    */
  11558.  /* software and incorporation in subsequent releases.               */
  11559.  /*                                                                  */
  11560.  /********************************************************************/
  11561.  
  11562. #pragma  csect(code,  "GG@VIEW ")
  11563. #pragma  csect(static,"GG$VIEW ")
  11564. #include "gg.h"
  11565.  
  11566. struct browser {
  11567.    struct gopherinfo    *ip;
  11568.    struct texthdr       *thp;            /* text header pointer      */
  11569.    struct textline     **tv;             /* text vector              */
  11570.                char     *bda;            /* dynamic area address     */
  11571.                char     *work;           /* find work area address   */
  11572.                char     *firstpos;       /* beginning of actual data */
  11573.                char     *lastpos;        /* end of actual data       */
  11574.                int       depth;          /* dynamic area depth       */
  11575.                int       lvl;            /* last visible line        */
  11576.                int       size;           /* dynamic area size        */
  11577.                int       more_rows;      /* Scroll request row count */
  11578.                int       rowfactor;      /* # physical rows per line */
  11579.                int       screenbump;     /* # physical rows * width  */
  11580.                int       top;            /* top row number           */
  11581.                int       total;          /* total number of rows     */
  11582.                int       coloff;         /* offset from LEFT/RIGHT   */
  11583.                int       cols;           /* 1 if COLS done, else 0   */
  11584.                int       maxlen;         /* maximum text length      */
  11585.                int       maxcoloff;      /* maximum right scroll     */
  11586.                Bool      override_scroll;/* set by some commands     */
  11587.                Bool      highlighted;    /* set if FIND highlights   */
  11588.                Bool      reinit_browse;  /* set if text changed      */
  11589.                Bool      exit_browse;    /* set if browse must exit  */
  11590.                Bool      find_hit_end;   /* top/bottom of data reach */
  11591.                int       find_count;     /* used by FIND ALL         */
  11592.                int       find_row;       /* row where last found     */
  11593.                int       find_col;       /* col where last found     */
  11594.                int       found_row;      /* row where last found     */
  11595.                int       found_col;      /* col where last found     */
  11596.                int       csrpos;         /* cursor position          */
  11597.                int       find_csrpos;    /* col where last found     */
  11598.                int       found_left;     /* pos left of found string */
  11599.                int       found_right;    /* pos right of found string*/
  11600.                char      cursor     [9]; /* cursor field name        */
  11601.                char      find_cursor[9]; /* row where last found     */
  11602.                char      title     [81]; /* title                    */
  11603.                char      cols_line [81]; /* cols line                */
  11604.                char      zcmd      [81]; /* command input            */
  11605.               };
  11606.  
  11607. /******* EXTRACT command **********************************************/
  11608.  
  11609. static Bool
  11610. process_extract_command(gp,bp,operands)
  11611. Rstruc ggcb         *gp;
  11612. Rstruc browser      *bp;
  11613. char                *operands;
  11614. {
  11615.  Rstruc gopherinfo  *ip = bp->ip;
  11616.  
  11617.  gp->extract_file = NULL;
  11618.  
  11619.  (void)GGMispf(gp,"CONTROL DISPLAY SAVE");
  11620.  (void)GGMxtx(gp,ip,EXTRACT_IT);                   /* Extract text */
  11621.  (void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
  11622.  
  11623.  return TRUE;
  11624. }
  11625.  
  11626. /******* PRINT command ************************************************/
  11627.  
  11628. static Bool
  11629. process_print_command(gp,bp,operands)
  11630. Rstruc ggcb         *gp;
  11631. Rstruc browser      *bp;
  11632. char                *operands;
  11633. {
  11634.  Rstruc gopherinfo  *ip = bp->ip;
  11635.  
  11636.  gp->extract_file = NULL;
  11637.  
  11638.  (void)GGMispf(gp,"CONTROL DISPLAY SAVE");
  11639.  (void)GGMxtx(gp,ip,PRINT_IT);                   /* Print text */
  11640.  (void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
  11641.  
  11642.  return TRUE;
  11643. }
  11644.  
  11645. /******* INFO command. ************************************************/
  11646.  
  11647. static Bool
  11648. process_info_command(gp,bp,operands)
  11649. Rstruc ggcb         *gp;
  11650. Rstruc browser      *bp;
  11651. char                *operands;
  11652. {
  11653.  Rstruc gopherinfo  *ip = bp->ip;
  11654.  
  11655.  if (!GGMinfo(gp,ip)) return FALSE;
  11656.  
  11657.  (void)GGMispf(gp,"CONTROL DISPLAY SAVE");
  11658.  (void)GGMvtx(gp,NULL,TRUE);              /* View text */
  11659.  (void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
  11660.  
  11661.  return TRUE;
  11662. }
  11663.  
  11664. /******* BOOKMARK command. ********************************************/
  11665.  
  11666. static Bool
  11667. process_bookmark_command(gp,bp,operands)
  11668. Rstruc ggcb         *gp;
  11669. Rstruc browser      *bp;
  11670. char                *operands;
  11671. {
  11672.  Rstruc gopherinfo  *ip = bp->ip;
  11673.  
  11674.  if (!GGMinfo(gp,ip)) return FALSE;
  11675.  
  11676.  gp->extract_file = NULL;
  11677.  
  11678.  (void)GGMispf(gp,"CONTROL DISPLAY SAVE");
  11679.  (void)GGMxtx(gp,ip,BOOKMARK_IT);       /* save as bookmark */
  11680.  (void)GGMispf(gp,"CONTROL DISPLAY RESTORE");
  11681.  
  11682.  return TRUE;
  11683. }
  11684.  
  11685. /******* OPTIONS command **********************************************/
  11686.  
  11687. static Bool
  11688. process_options_command(gp,bp,operands)
  11689. Rstruc ggcb         *gp;
  11690. Rstruc browser      *bp;
  11691. char                *operands;
  11692. {
  11693.  
  11694.  GGMdsopt(gp,operands);
  11695.  
  11696.  return TRUE;
  11697. }
  11698.  
  11699. /******* QUIT command *************************************************/
  11700.  
  11701. static Bool
  11702. process_quit_command(gp,bp,operands)
  11703. Rstruc ggcb         *gp;
  11704. Rstruc browser      *bp;
  11705. char                *operands;
  11706. {
  11707.  
  11708.  gp->quit = TRUE;
  11709.  
  11710.  return TRUE;
  11711. }
  11712.  
  11713. /******* COLS command *************************************************/
  11714.  
  11715. static Bool
  11716. process_cols_command(gp,bp,operands)
  11717. Rstruc ggcb         *gp;
  11718. Rstruc browser      *bp;
  11719. char                *operands;
  11720. {
  11721.  
  11722.  bp->cols = 1;
  11723.  *bp->cols_line = '\0';
  11724.  bp->reinit_browse = TRUE;
  11725.  return TRUE;
  11726. }
  11727.  
  11728. /******* RESET command ************************************************/
  11729.  
  11730. static Bool
  11731. process_reset_command(gp,bp,operands)
  11732. Rstruc ggcb         *gp;
  11733. Rstruc browser      *bp;
  11734. char                *operands;
  11735. {
  11736.  
  11737.  bp->cols = 0;
  11738.  *bp->cols_line = '\0';
  11739.  bp->reinit_browse = TRUE;
  11740.  return TRUE;
  11741. }
  11742.  
  11743. /******* DISPLAY command **********************************************/
  11744.  
  11745. static Bool
  11746. process_display_command(gp,bp,operands)
  11747. Rstruc ggcb         *gp;
  11748. Rstruc browser      *bp;
  11749. char                *operands;
  11750. {
  11751.  unsigned int        u;
  11752.  
  11753.  switch (strlen(operands)) {
  11754.    case 1: gp->text_dispchar = operands[0];
  11755.            break;
  11756.    case 2: if (1 != sscanf(operands,"%x",&u)) {
  11757.              ERR1("Invalid hex character representation.");
  11758.              return FALSE;
  11759.            }
  11760.            gp->text_dispchar = u;
  11761.            break;
  11762.    default:
  11763.            ERR1("A single character must be specified.");
  11764.            return FALSE;
  11765.  }
  11766.  bp->reinit_browse = TRUE;
  11767.  return TRUE;
  11768. }
  11769.  
  11770. /******* LOCATE command ***********************************************/
  11771.  
  11772. static Bool
  11773. process_locate_command(gp,bp,operands)
  11774. Rstruc ggcb         *gp;
  11775. Rstruc browser      *bp;
  11776. char                *operands;
  11777. {
  11778.  int                 locnum;
  11779.  char                junk[72];
  11780.  
  11781.  if (1 != sscanf(operands, "%d %s", &locnum, junk)) {
  11782.    ERR1("The LOCATE command requires a line number.");
  11783.    return FALSE;
  11784.  }
  11785.  
  11786.  bp->top = locnum;
  11787.  bp->more_rows = 0;
  11788.  bp->override_scroll = TRUE;
  11789.  bp->reinit_browse = TRUE;
  11790.  return TRUE;
  11791. }
  11792.  
  11793. /***** Helper functions for FIND **************************************/
  11794.  
  11795. /*--------------------------------------------------------------------*
  11796.  * Get quoted FIND string.                                            *
  11797.  *--------------------------------------------------------------------*/
  11798.  
  11799. static char *
  11800. get_quoted_find_string(gp,cp,qform)
  11801. Rstruc ggcb         *gp;
  11802. char                *cp;
  11803. char                *qform;
  11804. {
  11805.  char                quote     = *cp;
  11806.  char                termchar  = '\0';
  11807.  
  11808.  for (cp++;;cp++) {
  11809.    if (*cp == quote) {
  11810.      switch (*(cp+1)) {
  11811.        case '\0':
  11812.        case ' ':  termchar = '\0'; break;
  11813.        case 'c':
  11814.        case 'C':  termchar = 'C' ; break;
  11815.        case 't':
  11816.        case 'T':  termchar = 'T' ; break;
  11817.        case 'x':
  11818.        case 'X':  termchar = 'X' ; break;
  11819.        case 'p':
  11820.        case 'P':  termchar = 'P' ; break;
  11821.        default:   continue;
  11822.      }
  11823.      if (termchar) {
  11824.        switch (*(cp+2)) {
  11825.          case '\0':
  11826.          case ' ':  break;
  11827.          default:   continue;
  11828.        }
  11829.        if (*qform != FIND_QUOTED) {
  11830.          ERR1(
  11831.       "Invalid string; Do not surround a quoted string with letters.");
  11832.          *qform = FIND_BADFORM;
  11833.          return NULL;
  11834.        }
  11835.        else {
  11836.          switch (termchar) {
  11837.            case 'C': *qform = FIND_C; break;
  11838.            case 'T': *qform = FIND_T; break;
  11839.            case 'X': *qform = FIND_X; break;
  11840.            case 'P': *qform = FIND_P; break;
  11841.          }
  11842.          *cp = '\0'; /* kill the quote because it's the character */
  11843.          cp++;       /* that the caller will kill, not the quote */
  11844.        }
  11845.      }
  11846.      break;
  11847.    }
  11848.    else if (!*cp) {
  11849.      ERR1(
  11850.      "Missing quote; The FIND command requires balanced quote marks.");
  11851.      *qform = FIND_BADFORM;
  11852.      return NULL;
  11853.    }
  11854.  }
  11855.  return cp;
  11856. }
  11857.  
  11858. /*--------------------------------------------------------------------*
  11859.  * Get FIND operand.                                                  *
  11860.  *--------------------------------------------------------------------*/
  11861.  
  11862. static char *
  11863. get_find_operand(gp,opp,qform)
  11864. Rstruc ggcb     *gp;
  11865. char           **opp;
  11866. char            *qform;
  11867. {
  11868.  char           *cp    = *opp;
  11869.  char           *start = NULL;
  11870.  
  11871.  cp = skip_ISPF_whitespace(cp);
  11872.  
  11873.  if (!*cp) return NULL;
  11874.  if (*cp == '\'' || *cp == '"') {
  11875.    start = cp+1;
  11876.    *qform = FIND_QUOTED;
  11877.    if (!(cp = get_quoted_find_string(gp,cp,qform))) return NULL;
  11878.  }
  11879.  else if ((*(cp+1) == '\'' || *(cp+1) == '"')) {
  11880.    switch (*cp) {
  11881.      case 'c':
  11882.      case 'C': *qform = FIND_C; break;
  11883.      case 't':
  11884.      case 'T': *qform = FIND_T; break;
  11885.      case 'x':
  11886.      case 'X': *qform = FIND_X; break;
  11887.      case 'p':
  11888.      case 'P': *qform = FIND_P; break;
  11889.      default:  *qform = FIND_UNQUOTED; break;
  11890.    }
  11891.    if (*qform != FIND_UNQUOTED) {
  11892.      cp++;
  11893.      start = cp+1;
  11894.      if (!(cp = get_quoted_find_string(gp,cp,qform))) return NULL;
  11895.    }
  11896.    else {
  11897.      start = cp;
  11898.      find_ISPF_whitespace(cp,start);
  11899.    }
  11900.  }
  11901.  else {
  11902.    start = cp;
  11903.    *qform = FIND_UNQUOTED;
  11904.    find_ISPF_whitespace(cp,start);
  11905.  }
  11906.  if (*cp) {
  11907.    *cp  = '\0';
  11908.    *opp = cp+1;
  11909.  }
  11910.  else {
  11911.    *opp = cp;
  11912.  }
  11913.  return start;
  11914. }
  11915.  
  11916. /*--------------------------------------------------------------------*
  11917.  * Find it.                                                           *
  11918.  *--------------------------------------------------------------------*/
  11919.  
  11920. #define REND                 (r+(*tpp)->tab_expanded_text_length)
  11921. #define PRECEDED_BY_VERBIAGE (q>r && isalnum(*(q-1)))
  11922. #define FOLLOWED_BY_VERBIAGE (q+findlen<REND && isalnum(*(q+findlen)))
  11923.  
  11924. static Bool
  11925. find_it(gp,bp,find_string,findlen,
  11926.                           find_type,find_what,find_trans,
  11927.                           find_left_bound,find_right_bound)
  11928. Rstruc ggcb       *gp;
  11929. Rstruc browser    *bp;
  11930. char              *find_string;
  11931. int                findlen;
  11932. char               find_type;      /* chars word prefix suffix */
  11933. char               find_what;      /* next prev first last all */
  11934. char               find_trans;     /* caps asis generic        */
  11935. int                find_left_bound;
  11936. int                find_right_bound;
  11937. {
  11938.  struct textline **tpp;
  11939.  char             *p;
  11940.  char             *q;
  11941.  char             *r;
  11942.  int               row;
  11943.  int               col;
  11944.  int               complen;
  11945.  int               lcol;
  11946.  int               rcol;
  11947.  int               ecol;
  11948.  Bool              backward_find;
  11949.  
  11950.  lcol = find_left_bound - 1;
  11951.  rcol = find_right_bound - 1;
  11952.  row  = bp->find_row;
  11953.  col  = bp->find_col;
  11954.  
  11955.  switch (find_what) {
  11956.    case FIND_NEXT:
  11957.                     if (bp->find_hit_end) {
  11958.                       bp->find_hit_end = FALSE;
  11959.                       row = 0;
  11960.                       col = lcol;
  11961.                     }
  11962.                     else if (EQUAL(bp->find_cursor,"GGBDYNA")) {
  11963.                       row = bp->top+((bp->find_csrpos-1)/80)-bp->cols-1;
  11964.                       col = (bp->find_csrpos-1) % 80 + bp->coloff;
  11965.                       if (++col >= bp->maxlen) {
  11966.                         row++;
  11967.                         col = lcol;
  11968.                       }
  11969.                     }
  11970.                     else {
  11971.                       row = bp->top - 1;
  11972.                       if (row < 0) row = 0;
  11973.                       col = lcol;
  11974.                     }
  11975.                     backward_find = FALSE;
  11976.                     break;
  11977.    case FIND_PREV:
  11978.                     if (bp->find_hit_end) {
  11979.                       bp->find_hit_end = FALSE;
  11980.                       row = bp->total - 1;
  11981.                       col = rcol;
  11982.                     }
  11983.                     else if (EQUAL(bp->find_cursor,"GGBDYNA")) {
  11984.                       row = bp->top+((bp->find_csrpos-1)/80)-bp->cols-1;
  11985.                       col = (bp->find_csrpos-1) % 80 + bp->coloff;
  11986.                       if (--col < 0) {
  11987.                         row--;
  11988.                         col = rcol;
  11989.                       }
  11990.                     }
  11991.                     else {
  11992.                       row = bp->total - 1;
  11993.                       col = rcol;
  11994.                     }
  11995.                     backward_find = TRUE;
  11996.                     break;
  11997.    case FIND_FIRST:
  11998.                     if (bp->find_hit_end) {
  11999.                       bp->find_hit_end = FALSE;
  12000.                     }
  12001.                     row = 0;
  12002.                     col = lcol;
  12003.                     backward_find = FALSE;
  12004.                     break;
  12005.    case FIND_LAST:
  12006.                     if (bp->find_hit_end) {
  12007.                       bp->find_hit_end = FALSE;
  12008.                     }
  12009.                     row = bp->total - 1;
  12010.                     col = rcol;
  12011.                     backward_find = TRUE;
  12012.                     break;
  12013.    case FIND_ALL:
  12014.                     col++;
  12015.                     backward_find = FALSE;
  12016.                     break;
  12017.  }
  12018.  
  12019.  if (backward_find == FALSE) {
  12020.    /* forward find */
  12021.    if (col < lcol) col = lcol;
  12022.    else if (col > rcol) {
  12023.      col = lcol;
  12024.      row++;
  12025.    }
  12026.    for (tpp = &bp->tv[row]; row < bp->total; tpp++, col=lcol, row++) {
  12027.      ecol = (*tpp)->tab_expanded_text_length - 1;
  12028.      if (ecol > rcol) ecol = rcol;
  12029.      if (col > ecol) continue;
  12030.      p = (*tpp)->tab_expanded_text;
  12031.      if (find_trans == FIND_CAPS) {
  12032.        copy_uppercase(bp->work,p);
  12033.        r = bp->work;
  12034.      }
  12035.      else r = p;
  12036.      complen = ecol-col+1;
  12037.      for (q = r + col;;q++) {
  12038.        q = memchr(q,find_string[0],complen);
  12039.        if (!q) break;
  12040.        col = q - r;
  12041.        complen = ecol-col+1;
  12042.        if (complen < findlen) break;
  12043.        if (!memcmp(q,find_string,findlen)) {
  12044.          switch (find_type) {
  12045.            case FIND_CHARS:  break;
  12046.            case FIND_WORD:
  12047.                 if (PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  12048.                     continue;
  12049.                 break;
  12050.            case FIND_PREFIX:
  12051.                 if (PRECEDED_BY_VERBIAGE || !FOLLOWED_BY_VERBIAGE)
  12052.                     continue;
  12053.                 break;
  12054.            case FIND_SUFFIX:
  12055.                 if (!PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  12056.                    continue;
  12057.                 break;
  12058.          }
  12059.          bp->find_row = row;
  12060.          bp->find_col = col;
  12061.          return TRUE;
  12062.        }
  12063.      }
  12064.    }
  12065.    bp->find_row = 0;
  12066.    bp->find_col = 0;
  12067.    bp->find_hit_end = TRUE;
  12068.    return FALSE;
  12069.  }
  12070.  else {
  12071.    /* backward find */
  12072.    if (row >= bp->total) row = bp->total - 1;
  12073.    if (col > rcol-findlen+1) col = rcol-findlen+1;
  12074.    else if (col < lcol) {
  12075.      col = rcol-findlen+1;
  12076.      row--;
  12077.    }
  12078.    for (tpp=&bp->tv[row]; row >= 0; tpp--, col=rcol-findlen+1, row--) {
  12079.      ecol = (*tpp)->tab_expanded_text_length - 1;
  12080.      if (ecol > rcol) ecol = rcol;
  12081.      if (col > ecol) col = ecol;
  12082.      p = (*tpp)->tab_expanded_text;
  12083.      if (find_trans == FIND_CAPS) {
  12084.        copy_uppercase(bp->work,p);
  12085.        r = bp->work;
  12086.      }
  12087.      else r = p;
  12088.      for (q = r + col; q >= r; q--) {
  12089.        if (!memcmp(q,find_string,findlen)) {
  12090.          switch (find_type) {
  12091.            case FIND_CHARS:  break;
  12092.            case FIND_WORD:
  12093.                 if (PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  12094.                     continue;
  12095.                 break;
  12096.            case FIND_PREFIX:
  12097.                 if (PRECEDED_BY_VERBIAGE || !FOLLOWED_BY_VERBIAGE)
  12098.                     continue;
  12099.                 break;
  12100.            case FIND_SUFFIX:
  12101.                 if (!PRECEDED_BY_VERBIAGE || FOLLOWED_BY_VERBIAGE)
  12102.                    continue;
  12103.                 break;
  12104.          }
  12105.          col = q - r;
  12106.          bp->find_row = row;
  12107.          bp->find_col = col;
  12108.          return TRUE;
  12109.        }
  12110.      }
  12111.    }
  12112.    bp->find_row = bp->total - 1;
  12113.    bp->find_col = bp->maxlen;
  12114.    bp->find_hit_end = TRUE;
  12115.    return FALSE;
  12116.  }
  12117.  
  12118. }
  12119.  
  12120. /********* FIND command ***********************************************/
  12121.  
  12122. static Bool
  12123. process_find_command(gp,bp,operands)
  12124. Rstruc ggcb         *gp;
  12125. Rstruc browser      *bp;
  12126. char                *operands;
  12127. {
  12128.  char        *find_operand [64];
  12129.  char        *show_type;
  12130.  char        *cp;
  12131.  char        *opcopy;
  12132.  char        *op;
  12133.  char        *p;
  12134.  char        *q;
  12135.  char         find_qform   [64];
  12136.  Bool         finderror = FALSE;
  12137.  Bool         out_of_bounds = FALSE;
  12138.  int          find_operand_count;
  12139.  int          ox;
  12140.  int          find_left_bound;
  12141.  int          find_right_bound;
  12142.  int          n;
  12143.  int          len;
  12144.  int          findlen;
  12145.  char         find_what;      /* next prev first last all */
  12146.  char         find_type;      /* chars word prefix suffix */
  12147.  char         find_trans;     /* caps asis generic        */
  12148.  char         find_form;      /* unquoted quoted c x t p  */
  12149.  char         ff;             /* unquoted quoted c x t p  */
  12150.  Bool         hit_end                = FALSE;
  12151.  Bool         find_string_given      = FALSE;
  12152.  Bool         find_what_given        = FALSE;
  12153.  Bool         find_type_given        = FALSE;
  12154.  Bool         find_left_bound_given  = FALSE;
  12155.  Bool         find_right_bound_given = FALSE;
  12156.  char         operand_copy [81];
  12157.  char         find_string  [81];
  12158.  char         temp         [81];
  12159.  char         show_string [129];
  12160.  char         shortmsg    [129];
  12161.  char         longmsg     [129];
  12162.  
  12163.  strcpy(operand_copy,operands);
  12164.  
  12165.  find_operand_count = 0;
  12166.  for (ox = 0, opcopy = operand_copy; ox < 64; ox++) {
  12167.    ff = FIND_UNQUOTED;
  12168.    op = get_find_operand(gp,&opcopy,&ff);
  12169.    if (ff == FIND_BADFORM) return FALSE;
  12170.    if (!op) break;
  12171.    find_operand[ox] = op;
  12172.    find_qform[ox] = ff;
  12173.    find_operand_count++;
  12174.  }
  12175.  
  12176.  if (find_operand_count == 0) {
  12177.    if (!*gp->text_find_string) {
  12178.      ERR1("The first FIND command requires an operand.");
  12179.      return FALSE;
  12180.    }
  12181.    strcpy(find_string,gp->text_find_string);
  12182.    find_what        = gp->text_find_what;
  12183.    find_type        = gp->text_find_type;
  12184.    find_trans       = gp->text_find_trans;
  12185.    find_left_bound  = gp->text_find_left_bound;
  12186.    find_right_bound = gp->text_find_right_bound;
  12187.  }
  12188.  else {
  12189.    find_what        = FIND_NEXT;
  12190.    find_type        = FIND_CHARS;
  12191.    find_trans       = FIND_CAPS;
  12192.    find_left_bound  = 1;
  12193.    find_right_bound = bp->maxlen;
  12194.    for (ox = 0; ox < find_operand_count; ox++) {
  12195.      op = find_operand[ox];
  12196.      ff = find_qform[ox];
  12197.      if (ff != FIND_UNQUOTED) {
  12198.        if (find_string_given) finderror = TRUE;
  12199.        else {
  12200.          strcpy(find_string,op);
  12201.          find_form = ff;
  12202.          find_string_given = TRUE;
  12203.        }
  12204.      }
  12205.      else {
  12206.        copy_uppercase(temp,op);
  12207.        if (EQUAL(temp,"*")) {
  12208.          if (find_string_given) finderror = TRUE;
  12209.          else {
  12210.            strcpy(find_string,gp->text_find_string);
  12211.            find_form = ff;
  12212.            find_string_given = TRUE;
  12213.          }
  12214.        }
  12215.        else if (find_operand_count == 1) {
  12216.          strcpy(find_string,op);
  12217.          find_form = ff;
  12218.          find_string_given = TRUE;
  12219.        }
  12220.        else if (EQUAL(temp,"NEXT")) {
  12221.          if (find_what_given) finderror = TRUE;
  12222.          else {
  12223.            find_what = FIND_NEXT;
  12224.            find_what_given = TRUE;
  12225.          }
  12226.        }
  12227.        else if (EQUAL(temp,"PREV")) {
  12228.          if (find_what_given) finderror = TRUE;
  12229.          else {
  12230.            find_what = FIND_PREV;
  12231.            find_what_given = TRUE;
  12232.          }
  12233.        }
  12234.        else if (EQUAL(temp,"FIRST")) {
  12235.          if (find_what_given) finderror = TRUE;
  12236.          else {
  12237.            find_what = FIND_FIRST;
  12238.            find_what_given = TRUE;
  12239.          }
  12240.        }
  12241.        else if (EQUAL(temp,"LAST")) {
  12242.          if (find_what_given) finderror = TRUE;
  12243.          else {
  12244.            find_what = FIND_LAST;
  12245.            find_what_given = TRUE;
  12246.          }
  12247.        }
  12248.        else if (EQUAL(temp,"ALL")) {
  12249.          if (find_what_given) finderror = TRUE;
  12250.          else {
  12251.            find_what = FIND_ALL;
  12252.            find_what_given = TRUE;
  12253.          }
  12254.        }
  12255.        else if (EQUAL(temp,"CHARS")) {
  12256.          if (find_type_given) finderror = TRUE;
  12257.          else {
  12258.            find_type = FIND_CHARS;
  12259.            find_type_given = TRUE;
  12260.          }
  12261.        }
  12262.        else if (EQUAL(temp,"WORD")) {
  12263.          if (find_type_given) finderror = TRUE;
  12264.          else {
  12265.            find_type = FIND_WORD;
  12266.            find_type_given = TRUE;
  12267.          }
  12268.        }
  12269.        else if (EQUAL(temp,"PREFIX") || EQUAL(temp,"PRE")) {
  12270.          if (find_type_given) finderror = TRUE;
  12271.          else {
  12272.            find_type = FIND_PREFIX;
  12273.            find_type_given = TRUE;
  12274.          }
  12275.        }
  12276.        else if (EQUAL(temp,"SUFFIX") || EQUAL(temp,"SUF")) {
  12277.          if (find_type_given) finderror = TRUE;
  12278.          else {
  12279.            find_type = FIND_SUFFIX;
  12280.            find_type_given = TRUE;
  12281.          }
  12282.        }
  12283.        else if (*(temp+strspn(temp,"0123456789")) == '\0') {
  12284.          if (find_left_bound_given) {
  12285.            if (find_right_bound_given) finderror = TRUE;
  12286.            else {
  12287.              find_right_bound = atoi(temp);
  12288.              if (find_right_bound > bp->maxlen) out_of_bounds = TRUE;
  12289.              find_right_bound_given = TRUE;
  12290.            }
  12291.          }
  12292.          else {
  12293.            find_left_bound  = atoi(temp);
  12294.              if (find_right_bound < 1) out_of_bounds = TRUE;
  12295.            find_left_bound_given = TRUE;
  12296.          }
  12297.        }
  12298.        else {
  12299.          if (find_string_given) finderror = TRUE;
  12300.          else {
  12301.            strcpy(find_string,op);
  12302.            find_form = ff;
  12303.            find_string_given = TRUE;
  12304.          }
  12305.        }
  12306.      }
  12307.    }
  12308.  }
  12309.  
  12310.  if (out_of_bounds) {
  12311.    ERR2("Invalid bound; Bounds must lie between 1 and %d", bp->maxlen);
  12312.    return FALSE;
  12313.  }
  12314.  
  12315.  if (finderror) {
  12316.    ERR1("Put string in quotes; Conflicting or unknown parameter.");
  12317.    return FALSE;
  12318.  }
  12319.  
  12320.  len = strlen(find_string);
  12321.  
  12322.  if (find_string_given) bp->find_hit_end = FALSE;
  12323.  
  12324.  if (find_left_bound_given && find_right_bound_given
  12325.      && find_left_bound > find_right_bound) {
  12326.    n = find_left_bound;
  12327.    find_left_bound = find_right_bound;
  12328.    find_right_bound = n;
  12329.  }
  12330.  else if (find_left_bound_given && !find_right_bound_given) {
  12331.    find_right_bound = find_left_bound + len - 1;
  12332.  }
  12333.  
  12334.  if (find_string_given) {
  12335.    switch (find_form) {
  12336.      case FIND_UNQUOTED:  find_trans = FIND_CAPS;    break;
  12337.      case FIND_QUOTED:    find_trans = FIND_CAPS;    break;
  12338.      case FIND_C:         find_trans = FIND_ASIS;    break;
  12339.      case FIND_T:         find_trans = FIND_CAPS;    break;
  12340.      case FIND_P:         find_trans = FIND_GENERIC; break;
  12341.      case FIND_X:         find_trans = FIND_HEX;
  12342.         if (len % 2 != 0) {
  12343.           ERR1("Odd number of characters in hex string.");
  12344.           return FALSE;
  12345.         }
  12346.         if (len != strspn(find_string,"0123456789abcdefABCDEF")) {
  12347.           ERR1("Invalid (non-hex) characters in hex string.");
  12348.           return FALSE;
  12349.         }
  12350.         for (p = find_string, q = find_string; *p; p += 2, *q++) {
  12351.           sprintf(temp,"0x%2.2s",p);
  12352.           sscanf(temp,"%x",&n);
  12353.           *q = (char)n;
  12354.         }
  12355.         *q = '\0';
  12356.         len = strlen(find_string);
  12357.         break;
  12358.    }
  12359.  }
  12360.  
  12361.  /* Store parameters for next Repeat Find operation. */
  12362.  
  12363.  strcpy(gp->text_find_string,find_string);
  12364.  switch (find_what) {
  12365.    case FIND_PREV:
  12366.    case FIND_LAST:  gp->text_find_what = FIND_PREV; break;
  12367.    default:         gp->text_find_what = FIND_NEXT; break;
  12368.  }
  12369.  gp->text_find_type        = find_type;
  12370.  gp->text_find_trans       = find_trans;
  12371.  gp->text_find_left_bound  = find_left_bound;
  12372.  gp->text_find_right_bound = find_right_bound;
  12373.  
  12374.  if (!*find_string) {
  12375.    ERR1("A null string is not allowed for the FIND command.");
  12376.    return FALSE;
  12377.  }
  12378.  
  12379.  if (bp->total == 0) {
  12380.    ERR1("There is no text to search.");
  12381.    return FALSE;
  12382.  }
  12383.  
  12384.  strcpy(bp->zcmd,"");
  12385.  
  12386.  switch (find_type) {
  12387.    case FIND_CHARS:   show_type = "Chars";  break;
  12388.    case FIND_WORD:    show_type = "Word";   break;
  12389.    case FIND_PREFIX:  show_type = "Prefix"; break;
  12390.    case FIND_SUFFIX:  show_type = "Suffix"; break;
  12391.    default:           show_type = "Text";   break;
  12392.  }
  12393.  
  12394.  switch (find_trans) {
  12395.    case FIND_ASIS:    strcpy(show_string+0,"C'");
  12396.                       strcpy(show_string+2,find_string);
  12397.                       strcat(show_string,"'");
  12398.                       break;
  12399.    case FIND_GENERIC: strcpy(show_string+0,"P'");
  12400.                       strcpy(show_string+2,find_string);
  12401.                       strcat(show_string,"'");
  12402.                       break;
  12403.    case FIND_HEX:     strcpy(show_string+0,"X'");
  12404.                       for (p=find_string,q=show_string+2;*p;p++,q+=2) {
  12405.                         sprintf(q,"%2.2X",*p);
  12406.                       }
  12407.                       strcat(show_string,"'");
  12408.                       break;
  12409.    case FIND_CAPS:
  12410.    default:           strcpy(show_string+0,"'");
  12411.                       strcpy(show_string+1,find_string);
  12412.                       strcat(show_string,"'");
  12413.                       break;
  12414.  }
  12415.  
  12416.  switch (find_trans) {
  12417.    case FIND_CAPS:
  12418.         uppercase_in_place(find_string);
  12419.         break;
  12420.    case FIND_GENERIC:
  12421.         ERR1("The P'string' generic format is not supported.");
  12422.         return FALSE;
  12423.  }
  12424.  
  12425.  hit_end = bp->find_hit_end;
  12426.  findlen = strlen(find_string);
  12427.  
  12428.  if (find_what == FIND_ALL) {
  12429.    bp->find_count = 0;
  12430.    if (!find_it(gp,bp,find_string,findlen,
  12431.                                   find_type,FIND_FIRST,find_trans,
  12432.                                   find_left_bound, find_right_bound)) {
  12433.      sprintf(shortmsg,"No %s %s found",show_type,show_string);
  12434.      sprintf(longmsg,
  12435.              "%s %s - not found within columns %d to %d",
  12436.              show_type,show_string,find_left_bound,find_right_bound);
  12437.      ERR3("%24s;%s",shortmsg,longmsg);
  12438.      return FALSE;
  12439.    }
  12440.    bp->found_row = bp->find_row;
  12441.    bp->found_col = bp->find_col;
  12442.    bp->find_count = 1;
  12443.    while (find_it(gp,bp,find_string,findlen,
  12444.                         find_type,FIND_ALL,find_trans,
  12445.                         find_left_bound, find_right_bound)) {
  12446.          bp->find_count++;
  12447.    }
  12448.    bp->find_hit_end = FALSE;
  12449.  }
  12450.  else {
  12451.    if (!find_it(gp,bp,find_string,findlen,
  12452.                                   find_type,find_what,find_trans,
  12453.                                   find_left_bound, find_right_bound)) {
  12454.      if (hit_end) {
  12455.        sprintf(shortmsg,"No %s %s found",show_type,show_string);
  12456.        sprintf(longmsg,
  12457.                "%s %s - not found within columns %d to %d",
  12458.                show_type,show_string,find_left_bound,find_right_bound);
  12459.        ERR3("%24s;%s",shortmsg,longmsg);
  12460.        return FALSE;
  12461.      }
  12462.      else if (gp->text_find_what == FIND_PREV) {
  12463.        sprintf(shortmsg,"Top of data reached");
  12464.        sprintf(longmsg,
  12465.             "%s %s not found.  Use RFIND to continue from bottom.",
  12466.              show_type, show_string);
  12467.        ERR3("%24s;%s",shortmsg,longmsg);
  12468.      }
  12469.      else {
  12470.        sprintf(shortmsg,"Bottom of data reached");
  12471.        sprintf(longmsg,
  12472.                "%s %s not found.  Use RFIND to continue from top.",
  12473.              show_type, show_string);
  12474.        ERR3("%24s;%s",shortmsg,longmsg);
  12475.      }
  12476.      return FALSE;
  12477.    }
  12478.    bp->found_row = bp->find_row;
  12479.    bp->found_col = bp->find_col;
  12480.  }
  12481.  
  12482.  if (bp->found_row + 1 < bp->top
  12483.   || bp->found_row + 1 >= bp->top + bp->lvl - bp->cols) {
  12484.    bp->top = bp->found_row + 1 - 1;
  12485.    if (bp->top < 0) bp->top = 0;
  12486.  }
  12487.  
  12488.  if (bp->found_col < bp->coloff) {
  12489.    bp->coloff = bp->found_col;
  12490.    *bp->cols_line = '\0';
  12491.  }
  12492.  else if (bp->found_col+len > bp->coloff+80) {
  12493.    bp->coloff = bp->found_col + len - 80;
  12494.    if (bp->coloff < 0) bp->coloff = 0;
  12495.    *bp->cols_line = '\0';
  12496.  }
  12497.  
  12498.  strcpy(bp->cursor, "GGBDYNA");
  12499.  bp->csrpos = 80 * (bp->found_row - bp->top+bp->cols + 1)
  12500.               + bp->found_col - bp->coloff + 1;
  12501.  
  12502.  bp->found_left = bp->csrpos;
  12503.  bp->found_right = bp->found_left + len;
  12504.  bp->reinit_browse = TRUE;
  12505.  
  12506.  if (find_what == FIND_ALL) {
  12507.    sprintf(shortmsg,"%d %s %s",bp->find_count,show_type,show_string);
  12508.    sprintf(longmsg,
  12509.            "%s %s found %d times within columns %d to %d",
  12510.            show_type,show_string,bp->find_count,
  12511.            find_left_bound,find_right_bound);
  12512.    WARN3("%24s;%s",shortmsg,longmsg);
  12513.  }
  12514.  else {
  12515.    sprintf(shortmsg,"%s %s found",show_type,show_string);
  12516.    sprintf(longmsg,
  12517.            "Search for %s %s within columns %d to %d was successful",
  12518.            show_type,show_string, find_left_bound,find_right_bound);
  12519.    WARN3("%24s;%s",shortmsg,longmsg);
  12520.  }
  12521.  
  12522.  bp->find_row = bp->found_row;
  12523.  bp->find_col = bp->found_col;
  12524.  return TRUE;
  12525. }
  12526.  
  12527. /************ Fill browse dynamic area. *******************************/
  12528.  
  12529. static void
  12530. fill_browse_dynamic_area(gp,bp)
  12531. Rstruc ggcb        *gp;
  12532. Rstruc browser     *bp;
  12533. {
  12534.  struct textline  **tpp  = NULL;
  12535.  register char     *cp   = NULL;
  12536.  register char     *p;
  12537.  char              *q;
  12538.  char              *r;
  12539.  int                i;
  12540.  int                j;
  12541.  char               temp[12];
  12542.  
  12543.  static char  top_of_data_line[81] = "\
  12544. ********************************* Top of data \
  12545. **********************************";
  12546.  
  12547.  static char  bottom_of_data_line[81] = "\
  12548. ******************************** Bottom of data \
  12549. ********************************";
  12550.  
  12551.  bp->lastpos = bp->bda + bp->size;
  12552.  bp->total = bp->thp->text_line_count;
  12553.  
  12554.  memset(bp->bda,' ',bp->size);
  12555.  
  12556.  if      (bp->more_rows == -MAX_INT)
  12557.          bp->top = 0;
  12558.  else if (bp->more_rows == MAX_INT)
  12559.          bp->top = bp->total + 2 - bp->lvl + bp->cols;
  12560.  else    bp->top += bp->more_rows;
  12561.  
  12562.  if (bp->top < 0) bp->top = 0;
  12563.  if (bp->top > bp->total) bp->top = bp->total + 1;
  12564.  
  12565.  i  = bp->top;
  12566.  p  = bp->bda;
  12567.  
  12568.  if (bp->cols > 0) {
  12569.    if (!*bp->cols_line) {
  12570.      for (j=bp->coloff+1,r=bp->cols_line; j<=bp->coloff+80; j++,r++) {
  12571.        if (j%10 == 0) {
  12572.          sprintf(temp,"%d",j%100);
  12573.          *r = temp[0];
  12574.        }
  12575.        else if (j%5 == 0) *r = '+';
  12576.        else *r = '-';
  12577.      }
  12578.    }
  12579.    memcpy(p,bp->cols_line,80);
  12580.    p += 80;
  12581.  }
  12582.  
  12583.  if (i == 0) {
  12584.    memcpy(p,top_of_data_line,80);
  12585.    p += 80;
  12586.    i++;
  12587.  }
  12588.  
  12589.  bp->firstpos = p;
  12590.  
  12591.  for (tpp=&bp->tv[i-1];i<=bp->total && p<bp->lastpos;i++,tpp++,p+=80) {
  12592.    if ((*tpp)->tab_expanded_text_length > bp->coloff) {
  12593.      cp = (*tpp)->tab_expanded_text + bp->coloff;
  12594.      for (j = 0, q = p; *cp && j < 80; j++, q++, cp++) {
  12595.        if (*cp > 0xf9 || *cp < 0x40) *q = gp->text_dispchar;
  12596.        else *q = *cp;
  12597.      }
  12598.    }
  12599.  }
  12600.  
  12601.  if (p < bp->lastpos) {
  12602.    memcpy(p,bottom_of_data_line,80);
  12603.  }
  12604.  
  12605.  return;
  12606. }
  12607.  
  12608. /************ Highlight browse text. **********************************/
  12609.  
  12610. static void
  12611. highlight_browse_text(gp,bp)
  12612. Rstruc ggcb        *gp;
  12613. Rstruc browser     *bp;
  12614. {
  12615.  char              *p;
  12616.  
  12617.  bp->highlighted = FALSE;
  12618.  
  12619.  if (bp->found_left) {
  12620.    if (EQUAL(bp->cursor,"GGBDYNA")) {
  12621.      for (p = bp->bda + bp->found_left - 1; p >= bp->firstpos; p--) {
  12622.        if (*p == ' ') {
  12623.          *p = DATAOUT_HIGH;
  12624.          bp->highlighted = TRUE;
  12625.          break;
  12626.        }
  12627.      }
  12628.      for (p = bp->bda + bp->found_right - 1; p <= bp->lastpos; p++) {
  12629.       if (*p == ' ') {
  12630.         *p = DATAOUT_LOW;
  12631.          bp->highlighted = TRUE;
  12632.          break;
  12633.        }
  12634.      }
  12635.    }
  12636.  }
  12637.  
  12638.  bp->found_left = 0;
  12639.  bp->found_right = 0;
  12640.  
  12641.  return;
  12642. }
  12643.  
  12644. /************ Display browse data. ************************************/
  12645.  
  12646. static void
  12647. display_browse_data(gp,bp)
  12648. Rstruc ggcb        *gp;
  12649. Rstruc browser     *bp;
  12650. {
  12651.  Rstruc cmddesc    *cdp;
  12652.  char              *cp;
  12653.  char              *operands;
  12654.  int                displayrc;
  12655.  int                zscrolln;
  12656.  int                leftcol;
  12657.  int                rightcol;
  12658.  int                command_index;
  12659.  Bool               command_processed_ok;
  12660.  Bool               is_max;
  12661.  Bool               is_scroll_word;
  12662.  Bool               is_scroll_cursor;
  12663.  SCROLL             scroll_amount;
  12664.  char               command    [COMMANDSIZE+1];
  12665.  char               zverb      [16];
  12666.  char               zscrolla   [16];
  12667.  char               longmsg    [73];
  12668.  char               ggbtitle  [129];
  12669.  char               ggbmsg     [81];
  12670.  char               temp1      [81];
  12671.  char               temp2      [81];
  12672.  
  12673. static struct cmddesc browse_commands[] = {
  12674.                           {"L          ",process_locate_command   },
  12675.                           {"LOC        ",process_locate_command   },
  12676.                           {"LOCATE     ",process_locate_command   },
  12677.                           {"F          ",process_find_command     },
  12678.                           {"FIND       ",process_find_command     },
  12679.                           {"RFIND      ",process_find_command     },
  12680.                           {"YRFIND     ",process_find_command     },
  12681.                           {"COL        ",process_cols_command     },
  12682.                           {"COLS       ",process_cols_command     },
  12683.                           {"RES        ",process_reset_command    },
  12684.                           {"RESET      ",process_reset_command    },
  12685.                           {"NOCOL      ",process_reset_command    },
  12686.                           {"NOCOLS     ",process_reset_command    },
  12687.                           {"DISP       ",process_display_command  },
  12688.                           {"DISPL      ",process_display_command  },
  12689.                           {"DISPLAY    ",process_display_command  },
  12690.                           {"EXT        ",process_extract_command  },
  12691.                           {"EXTR       ",process_extract_command  },
  12692.                           {"EXTRACT    ",process_extract_command  },
  12693.                           {"PRT        ",process_print_command    },
  12694.                           {"PRNT       ",process_print_command    },
  12695.                           {"PRINT      ",process_print_command    },
  12696.                           {"INFO       ",process_info_command     },
  12697.                           {"BOOK       ",process_bookmark_command },
  12698.                           {"BOOKMARK   ",process_bookmark_command },
  12699.                           {"OPT        ",process_options_command  },
  12700.                           {"OPTION     ",process_options_command  },
  12701.                           {"OPTIONS    ",process_options_command  },
  12702.                           {"QUIT       ",process_quit_command     },
  12703.                           {"           ",NULL}
  12704.                          };
  12705.  
  12706.  bp->more_rows = 0;
  12707.  bp->override_scroll = FALSE;
  12708.  bp->exit_browse     = FALSE;
  12709.  
  12710.  memset (ggbtitle, '-', 80);
  12711.  strcpy (ggbtitle, "Browse - ");
  12712.  memcpy (ggbtitle + 9, bp->title, strlen(bp->title));
  12713.  *(ggbtitle + 9 + strlen(bp->title)) = ' ';
  12714.  
  12715.  
  12716.  if (!gp->setmsg) {
  12717.    leftcol = bp->coloff + 1;
  12718.    rightcol = bp->coloff + 80;
  12719.    if (bp->top > bp->total) strcpy(temp1,"");
  12720.    else sprintf(temp1, " Line %d of %d,", bp->top, bp->total);
  12721.    if (bp->maxlen <= 80)
  12722.         sprintf(temp2," Cols %d-%d",leftcol,rightcol);
  12723.    else sprintf(temp2," Cols %d-%d of %d",leftcol,rightcol,bp->maxlen);
  12724.    strcpy(ggbmsg,temp1);
  12725.    strcat(ggbmsg,temp2);
  12726.    strcpy (ggbtitle + 79 - strlen(ggbmsg), ggbmsg);
  12727.  }
  12728.  
  12729.  (void)GGMivput(gp,"GGBTITLE ",ggbtitle    ,-1);
  12730.  (void)GGMivput(gp,"ZCMD "    ,bp->zcmd    ,-1);
  12731.  (void)GGMivput(gp,"GGBDYNA " ,bp->bda     ,bp->size);
  12732.  (void)GGMivput(gp,"GGBCUR "  ,bp->cursor  ,-1);
  12733.  sprintf(temp1,"%d",bp->csrpos);
  12734.  (void)GGMivput(gp,"GGBPOS  " ,temp1       ,-1);
  12735.  (void)GGMivput(gp,"YRFIND "  ,"ALIAS FIND",-1);
  12736.  
  12737.  displayrc = GGMdispl(gp,"GGMVIEW ");
  12738.  
  12739.  if (displayrc > 0) bp->exit_browse = TRUE;
  12740.  
  12741.  (void)GGMivput(gp,"YRFIND "  ,"",-1);
  12742.  (void)GGMivget(gp,"GGBCUR  " ,bp->cursor  , 8);
  12743.  (void)GGMivget(gp,"ZCMD    " ,bp->zcmd     ,sizeof(bp->zcmd));
  12744.  bp->lvl    = GGMiget(gp,"GGBLVL  ");
  12745.  bp->csrpos = GGMiget(gp,"GGBPOS  ");
  12746.  
  12747.  strcpy(bp->find_cursor, bp->cursor);
  12748.  bp->find_csrpos = bp->csrpos;
  12749.  strcpy(bp->cursor,"");
  12750.  bp->csrpos = 1;
  12751.  if (bp->highlighted) bp->reinit_browse = TRUE;
  12752.  else                 bp->reinit_browse = FALSE;
  12753.  
  12754.  if (*bp->zcmd) {
  12755.  
  12756.    memset(command,' ',COMMANDSIZE);
  12757.    command_index = 0;
  12758.    for (cp = bp->zcmd; *cp && !isspace(*cp); cp++) {
  12759.      if (cp >= bp->zcmd+COMMANDSIZE) {
  12760.        ERR1(
  12761. "Enter EXTract, PRT, BOOKmark, INFO, OPTions, or a browse command.");
  12762.        command_processed_ok = FALSE;
  12763.      }
  12764.      command[command_index++] = toupper(*cp);
  12765.    }
  12766.    while (*cp && isspace(*cp)) cp++;
  12767.  
  12768.    for (cdp=browse_commands; *cdp->command_name != ' '; cdp++) {
  12769.      if (!memcmp(command,cdp->command_name,COMMANDSIZE-1)) {
  12770.        command_processed_ok = (cdp->command_processor)(gp,bp,cp);
  12771.        cdp = NULL;
  12772.        break;
  12773.      }
  12774.    }
  12775.    if (cdp) {
  12776.      ERR1(
  12777. "Enter EXTract, PRT, BOOKmark, INFO, OPTions, or a browse command.");
  12778.      command_processed_ok = FALSE;
  12779.    }
  12780.  
  12781.    if (command_processed_ok) strcpy(bp->zcmd,"");
  12782.  
  12783.  }
  12784.  
  12785.  if (gp->quit || bp->exit_browse) return;
  12786.  
  12787.  /* Check scroll request (ZSCROLLA direction, ZSCROLLN number).
  12788.   * Skip this if something was done by a command which causes
  12789.   * its own pseudo-scrolling to happen (like LOCATE).
  12790.   */
  12791.  
  12792.  if (!bp->override_scroll) {
  12793.  
  12794.    zscrolln = 0;
  12795.  
  12796.    (void)GGMivget(gp,"ZVERB    " ,  zverb    ,sizeof(zverb));
  12797.    (void)GGMivget(gp,"ZSCROLLA " ,  zscrolla ,sizeof(zscrolla));
  12798.    zscrolln = GGMiget(gp,"ZSCROLLN ");
  12799.  
  12800.    is_max = FALSE;
  12801.    is_scroll_word = FALSE;
  12802.    is_scroll_cursor = FALSE;
  12803.  
  12804.    switch (zscrolla[0]) {
  12805.      case 'P':
  12806.      case 'H':
  12807.      case 'D':  is_scroll_word = TRUE;
  12808.                 break;
  12809.      case 'C':  is_scroll_word = TRUE;
  12810.                 is_scroll_cursor = TRUE;
  12811.                 break;
  12812.      case 'M':  is_max = TRUE;
  12813.                 break;
  12814.    }
  12815.  
  12816.    if      (EQUAL(zverb,"DOWN"))  scroll_amount = DOWN;
  12817.    else if (EQUAL(zverb,"UP"))    scroll_amount = UP;
  12818.    else if (EQUAL(zverb,"LEFT"))  scroll_amount = LEFT;
  12819.    else if (EQUAL(zverb,"RIGHT")) scroll_amount = RIGHT;
  12820.    else                           scroll_amount = NO_SCROLL;
  12821.  
  12822.  
  12823.    switch (scroll_amount) {
  12824.      case NO_SCROLL:
  12825.           bp->more_rows = 0;
  12826.           break;
  12827.      case DOWN:
  12828.           if (is_max) bp->more_rows = MAX_INT;
  12829.           else if (is_scroll_word)
  12830.                       bp->more_rows = zscrolln - bp->cols;
  12831.           else        bp->more_rows = zscrolln;
  12832.           bp->reinit_browse = TRUE;
  12833.           break;
  12834.      case UP:
  12835.           if (is_max) bp->more_rows = -MAX_INT;
  12836.           else if (is_scroll_cursor)
  12837.                       bp->more_rows = -zscrolln;
  12838.           else if (is_scroll_word)
  12839.                       bp->more_rows = -zscrolln - bp->cols;
  12840.           else        bp->more_rows = -zscrolln;
  12841.           bp->reinit_browse = TRUE;
  12842.           break;
  12843.      case LEFT:
  12844.           if (is_max) bp->coloff = 0;
  12845.           else        bp->coloff -= zscrolln;
  12846.           if (bp->coloff < 0) bp->coloff = 0;
  12847.           *bp->cols_line = '\0';
  12848.           bp->more_rows = 0;
  12849.           bp->reinit_browse = TRUE;
  12850.           break;
  12851.      case RIGHT:
  12852.           if (is_max) bp->coloff = bp->maxcoloff;
  12853.           else        bp->coloff += zscrolln;
  12854.           if (bp->coloff > bp->maxcoloff) bp->coloff = bp->maxcoloff;
  12855.           *bp->cols_line = '\0';
  12856.           bp->more_rows = 0;
  12857.           bp->reinit_browse = TRUE;
  12858.           break;
  12859.    }
  12860.  }
  12861.  
  12862.  return;
  12863. }
  12864.  
  12865. /****** View text in full screen mode (BROWSE replacement) ***********/
  12866.  
  12867. void
  12868. GGMview(gp,ip,texthdrp,title)
  12869. Rstruc ggcb         *gp;
  12870. Rstruc gopherinfo   *ip;
  12871. struct texthdr      *texthdrp;
  12872. char                *title;
  12873. {
  12874.  struct textline    *tp;
  12875.  struct textline   **tv;
  12876.  struct textline   **textvector;
  12877.  struct browser     *bp;
  12878.  struct browser      browserstruct;
  12879.  
  12880.  GETMAIN(textvector, struct textline *,
  12881.          texthdrp->text_line_count, "text vector");
  12882.  if (!textvector) {
  12883.    ERR1("Not enough memory to display text.");
  12884.    return;
  12885.  }
  12886.  
  12887.  bp = &browserstruct;
  12888.  memset(bp,0,sizeof(struct browser));
  12889.  bp->ip = ip;
  12890.  bp->thp = texthdrp;
  12891.  bp->tv = textvector;
  12892.  strcpy(bp->title,title);
  12893.  bp->more_rows = -MAX_INT;   /* set initial request to scroll up max */
  12894.  bp->top       = 0;
  12895.  bp->find_row  = -1;
  12896.  bp->find_col  = -1;
  12897.  bp->csrpos    = 1;
  12898.  strcpy(bp->cursor,"");
  12899.  bp->reinit_browse = TRUE;
  12900.  
  12901.  /* Collect text line pointers, skipping suppressed lines. */
  12902.  
  12903.  bp->maxlen = 0;
  12904.  for (tp=texthdrp->first_text_line, tv=textvector; tp; tp=tp->next) {
  12905.    if (tp->text_length >= 0) {
  12906.      *(tv++) = tp;
  12907.      if (bp->maxlen < tp->tab_expanded_text_length)
  12908.          bp->maxlen = tp->tab_expanded_text_length;
  12909.    }
  12910.  }
  12911.  bp->maxcoloff = bp->maxlen - 80;
  12912.  if (bp->maxcoloff < 0) bp->maxcoloff = 0;
  12913.  
  12914.  GETMAIN(bp->work, char *, bp->maxlen+1, "browse work string");
  12915.  if (!bp->work) return;
  12916.  
  12917.  (void)GGMispf(gp,
  12918.          "PQUERY PANEL(GGMVIEW) AREANAME(GGBDYNA) DEPTH(GGBDEPTH)");
  12919.  if (gp->ispfrc != 0) return;
  12920.  bp->depth = GGMiget(gp,"GGBDEPTH ");
  12921.  bp->size = bp->depth * 80;
  12922.  GETMAIN(bp->bda, char *, bp->size+1, "browse dynamic area");
  12923.  if (!bp->bda) return;
  12924.  
  12925.  if (!gp->text_dispchar) gp->text_dispchar = '.';
  12926.  
  12927.  for (;;) {
  12928.    if (bp->reinit_browse) {
  12929.      fill_browse_dynamic_area(gp,bp);
  12930.      highlight_browse_text(gp,bp);
  12931.    }
  12932.    display_browse_data(gp,bp);
  12933.    if (gp->quit || bp->exit_browse) break;
  12934.  }
  12935.  
  12936.  FREEMAIN(bp->work,"browse work string");
  12937.  FREEMAIN(bp->bda,"browse dynamic area");
  12938.  FREEMAIN(textvector, "text vector");
  12939.  
  12940.  return;
  12941. }
  12942.  
  12943. ./ ADD NAME=GGMVTX
  12944.  
  12945.  /********************************************************************/
  12946.  /*                                                                  */
  12947.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  12948.  /*                                                                  */
  12949.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  12950.  /*                                                                  */
  12951.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  12952.  /* including the implied warranties of merchantability and fitness, */
  12953.  /* are expressly denied.                                            */
  12954.  /*                                                                  */
  12955.  /* Provided this copyright notice is included, this software may    */
  12956.  /* be freely distributed and not offered for sale.                  */
  12957.  /*                                                                  */
  12958.  /* Changes or modifications may be made and used only by the maker  */
  12959.  /* of same, and not further distributed.  Such modifications should */
  12960.  /* be mailed to the author for consideration for addition to the    */
  12961.  /* software and incorporation in subsequent releases.               */
  12962.  /*                                                                  */
  12963.  /********************************************************************/
  12964.  
  12965. #pragma  csect(code,  "GG@VTX  ")
  12966. #pragma  csect(static,"GG$VTX  ")
  12967. #include "gg.h"
  12968.  
  12969. /****** View the lines of text retrieved from the server. ************/
  12970.  
  12971. Bool
  12972. GGMvtx(gp,ip,how)
  12973. Rstruc ggcb         *gp;
  12974. Rstruc gopherinfo   *ip;
  12975. GOHOW                how;
  12976. {
  12977.  struct texthdr     *texthdrp;
  12978.  char                title     [81];
  12979.  
  12980.  switch (how) {
  12981.    case AS_NOTHING: return;
  12982.    default:         break;
  12983.  }
  12984.  
  12985.  texthdrp = (ip ? &ip->thdr : &gp->thdr);
  12986.  
  12987.  if (!ip) sprintf(title, "GopherServer:%s ",gp->ggserver);
  12988.  else     strncpy(title, ip->desc, sizeof(title));
  12989.  
  12990.  GGMview(gp,ip,texthdrp,title);
  12991.  
  12992.  return;
  12993. }
  12994.  
  12995. ./ ADD NAME=GGMWAIS
  12996.  
  12997.  /********************************************************************/
  12998.  /*                                                                  */
  12999.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  13000.  /*                                                                  */
  13001.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  13002.  /*                                                                  */
  13003.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  13004.  /* including the implied warranties of merchantability and fitness, */
  13005.  /* are expressly denied.                                            */
  13006.  /*                                                                  */
  13007.  /* Provided this copyright notice is included, this software may    */
  13008.  /* be freely distributed and not offered for sale.                  */
  13009.  /*                                                                  */
  13010.  /* Changes or modifications may be made and used only by the maker  */
  13011.  /* of same, and not further distributed.  Such modifications should */
  13012.  /* be mailed to the author for consideration for addition to the    */
  13013.  /* software and incorporation in subsequent releases.               */
  13014.  /*                                                                  */
  13015.  /********************************************************************/
  13016.  
  13017. #pragma  csect(code,  "GG@WAIS ")
  13018. #pragma  csect(static,"GG$WAIS ")
  13019. #include "gg.h"
  13020.  
  13021. /****** Gopher WAIS interface. *************************************/
  13022.  
  13023. Bool
  13024. GGMwais(gp,ip,how)
  13025. Rstruc ggcb        *gp;
  13026. Rstruc gopherinfo  *ip;
  13027. GOHOW               how;
  13028. {
  13029.  Rstruc connection *sp;
  13030.  char              *lp;
  13031.  char               ggwaisq[256];
  13032.  
  13033.  sp = &gp->gopher_connection;
  13034.  
  13035.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  13036.  
  13037.  strcpy(ggwaisq,"");
  13038.  
  13039.  GGMispf(gp,"VGET (GGWAISQ) PROFILE");
  13040.  
  13041.  if (GGMdispl(gp,"GGMPWAIS") > 0) return FALSE;
  13042.  
  13043.  GGMivget(gp,"GGWAISQ ",ggwaisq, sizeof(ggwaisq));
  13044.  
  13045.  if (!*ip->path) strcpy(gp->gopher_command, ggwaisq);
  13046.  else            sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwaisq);
  13047.  
  13048.  gp->ginfo = ip;
  13049.  
  13050.  if (!GGMconn(gp,sp)) return FALSE; /* Connect to gopher server */
  13051.  
  13052.  GOPHERSEND(gp,sp);                   /* Send socket command */
  13053.  
  13054.  GGMclrtx(gp,ip);                  /* Clear text */
  13055.  
  13056.  sp->receiving_text = TRUE;
  13057.  
  13058.  do {
  13059.    if (GGMgsrvl(gp,sp,&lp,TRUE)) {         /* Get server line */
  13060.      if (lp) {
  13061.        (void)GGMouttx(gp,lp,ip);          /* Output text line */
  13062.      }
  13063.    }
  13064.  } while (lp);                            /* until no more lines */
  13065.  
  13066.  if (sp->time_to_go_home) {
  13067.    WARN2("No data available from server %s.\n",gp->ggserver);
  13068.    return FALSE;
  13069.  }
  13070.  
  13071.  if (sp->connected_to_server) {
  13072.    (void)GGMdisc(gp,sp);           /* Disconnect from gopher server */
  13073.  }
  13074.  
  13075.  GGMdir(gp,ip,how); /* display entries returned from WAIS server */
  13076.  
  13077.  return TRUE;
  13078.  
  13079. }
  13080.  
  13081. ./ ADD NAME=GGMWHOIS
  13082.  
  13083.  /********************************************************************/
  13084.  /*                                                                  */
  13085.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  13086.  /*                                                                  */
  13087.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  13088.  /*                                                                  */
  13089.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  13090.  /* including the implied warranties of merchantability and fitness, */
  13091.  /* are expressly denied.                                            */
  13092.  /*                                                                  */
  13093.  /* Provided this copyright notice is included, this software may    */
  13094.  /* be freely distributed and not offered for sale.                  */
  13095.  /*                                                                  */
  13096.  /* Changes or modifications may be made and used only by the maker  */
  13097.  /* of same, and not further distributed.  Such modifications should */
  13098.  /* be mailed to the author for consideration for addition to the    */
  13099.  /* software and incorporation in subsequent releases.               */
  13100.  /*                                                                  */
  13101.  /********************************************************************/
  13102.  
  13103. #pragma  csect(code,  "GG@WHOIS")
  13104. #pragma  csect(static,"GG$WHOIS")
  13105. #include "gg.h"
  13106.  
  13107. /****** Gopher WHOIS/FINGER interface. *****************************/
  13108.  
  13109. Bool
  13110. GGMwhois(gp,ip,how)
  13111. Rstruc ggcb        *gp;
  13112. Rstruc gopherinfo  *ip;
  13113. GOHOW               how;            /* ignored */
  13114. {
  13115.  Rstruc connection *sp;
  13116.  char              *lp;
  13117.  Bool               got_some;
  13118.  char               ggwhoisq[256];
  13119.  
  13120.  sp = &gp->gopher_connection;
  13121.  
  13122.  strcpy(gp->ggserver,ip->host);     /* Specify server to connect to */
  13123.  
  13124.  strcpy(ggwhoisq,"");
  13125.  
  13126.  GGMispf(gp,"VGET (GGWHOISQ) PROFILE");
  13127.  
  13128.  if (GGMdispl(gp,"GGMPWHOI") > 0) return FALSE;
  13129.  
  13130.  GGMivget(gp,"GGWHOISQ ",ggwhoisq, sizeof(ggwhoisq));
  13131.  
  13132.  if (!*ip->path) strcpy(gp->gopher_command, ggwhoisq);
  13133.  else            sprintf(gp->gopher_command,"%s\t%s",ip->path,ggwhoisq);
  13134.  
  13135.  gp->ginfo = ip;
  13136.  
  13137.  if (!GGMconn(gp,sp)) return FALSE;   /* Connect to gopher server */
  13138.  
  13139.  GOPHERSEND(gp,sp);                   /* Send socket command */
  13140.  
  13141.  GGMclrtx(gp,ip);                  /* Clear text */
  13142.  
  13143.  sp->receiving_text = TRUE;
  13144.  got_some = FALSE;
  13145.  do {
  13146.    if (GGMgsrvl(gp,sp,&lp,TRUE)) {         /* Get server line */
  13147.      if (lp) {
  13148.        got_some = TRUE;
  13149.        (void)GGMouttx(gp,lp,ip);          /* Output text line */
  13150.      }
  13151.    }
  13152.  } while (lp);                            /* until no more lines */
  13153.  
  13154.  if (!got_some) {
  13155.    WARN2("No data available from server %s.\n",gp->ggserver);
  13156.    return FALSE;
  13157.  }
  13158.  
  13159.  if (sp->connected_to_server) {
  13160.    (void)GGMdisc(gp,sp);         /* Disconnect from gopher server */
  13161.  }
  13162.  
  13163.  GGMvtx(gp,ip,how);      /* display text from WHOIS/FINGER server */
  13164.  
  13165.  return TRUE;
  13166.  
  13167. }
  13168.  
  13169. ./ ADD NAME=GGMXTX
  13170.  
  13171.  /********************************************************************/
  13172.  /*                                                                  */
  13173.  /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992    */
  13174.  /*                                                                  */
  13175.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  13176.  /*                                                                  */
  13177.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  13178.  /* including the implied warranties of merchantability and fitness, */
  13179.  /* are expressly denied.                                            */
  13180.  /*                                                                  */
  13181.  /* Provided this copyright notice is included, this software may    */
  13182.  /* be freely distributed and not offered for sale.                  */
  13183.  /*                                                                  */
  13184.  /* Changes or modifications may be made and used only by the maker  */
  13185.  /* of same, and not further distributed.  Such modifications should */
  13186.  /* be mailed to the author for consideration for addition to the    */
  13187.  /* software and incorporation in subsequent releases.               */
  13188.  /*                                                                  */
  13189.  /********************************************************************/
  13190.  
  13191. #pragma  csect(code,  "GG@XTX  ")
  13192. #pragma  csect(static,"GG$XTX  ")
  13193. #include "gg.h"
  13194.  
  13195. #define XFPUTC(A)     gp->extract_write_error = (fputc((A),xfp) == EOF)
  13196.  
  13197. #define XFWRITE(A,B)  fwrite((A),(B),1,xfp), \
  13198.                       gp->extract_write_error = (ferror(xfp) != 0)
  13199.  
  13200. /****** Extract the lines of server text into a data set. ************/
  13201.  
  13202. Bool
  13203. GGMxtx(gp,ip,ex)
  13204. Rstruc ggcb         *gp;
  13205. Rstruc gopherinfo   *ip;
  13206. EXTREQ               ex;
  13207. {
  13208.  FILE               *xfp;
  13209.  struct texthdr     *thp;
  13210.  struct textline    *tp;
  13211.  struct extraction  *ep;
  13212.  char               *cp;
  13213.  int                 l;
  13214.  int                 linelen;
  13215.  Bool                final;
  13216.  char                formatted_number [11];
  13217.  struct extraction   the_extraction;
  13218.  
  13219.  thp = (ip && ex != BOOKMARK_IT ? &ip->thdr : &gp->thdr);
  13220.  
  13221.  /* Set article data for message. */
  13222.  
  13223.  if (ip) {
  13224.    sprintf(formatted_number,"%d",ip->type);
  13225.    (void)GGMivput(gp,"GGTNUM ",  formatted_number, -1);
  13226.    (void)GGMivput(gp,"GGTSUBJ ", ip->desc,         -1);
  13227.  }
  13228.  
  13229.  if (gp->extract_file) {
  13230.    (void)GGMispf(gp,"CONTROL DISPLAY LOCK");
  13231.      switch (ex) {
  13232.        case PRINT_IT: GGMispf(gp,"DISPLAY PANEL(GGMLPRN2)"); break;
  13233.        default:       GGMispf(gp,"DISPLAY PANEL(GGMLEXN2)"); break;
  13234.      }
  13235.    xfp = gp->extract_file;
  13236.    ep = gp->extractionp;
  13237.  }
  13238.  else {
  13239.  
  13240.    ep = &the_extraction;
  13241.    memset(ep,0,sizeof(struct extraction));
  13242.    switch (ex) {
  13243.      case EXTRACT_IT:  ep->mode = SEQ;
  13244.                        strcpy(ep->panelname,"GGMPEXDS");
  13245.                        break;
  13246.      case PRINT_IT:    ep->mode = JES;
  13247.                        strcpy(ep->panelname,"GGMPPRDS");
  13248.                        break;
  13249.      case BOOKMARK_IT: ep->mode = SEQ;
  13250.                        strcpy(ep->panelname,"GGMPBMDS");
  13251.                        break;
  13252.    }
  13253.    ep->ex = ex;
  13254.  
  13255.    if (ip) GGMivput(gp,"GGTSUBJ ",ip->desc,-1);
  13256.    else    GGMivput(gp,"GGTSUBJ ",""      ,-1);
  13257.  
  13258.    if (!((xfp=GGMgetds(gp,ep)))) return FALSE;
  13259.  
  13260.    gp->extract_tab_expanding          = ep->tab_expanding;
  13261.    gp->extract_appending              = ep->appending;
  13262.    gp->extract_blank_before_separator = ep->blanking;
  13263.    gp->extract_separator_line         = ep->separator;
  13264.  }
  13265.  
  13266.  gp->extract_write_error = FALSE;
  13267.  gp->extract_close_error = FALSE;
  13268.  
  13269.  /* If a bookmark, then write gopher menu header only if this is
  13270.   * a new data set (not appending).
  13271.   */
  13272.  
  13273.  if (ep->ex == BOOKMARK_IT && !ep->appending) {
  13274.    XFWRITE(MENUIDENT,strlen(MENUIDENT));
  13275.    XFPUTC('\n');
  13276.  }
  13277.  
  13278.  /* If append mode, and a separator line was specified, use it. */
  13279.  
  13280.  if (gp->extract_appending) {
  13281.    XFPUTC('\n');
  13282.    if (gp->extract_separator_line && *gp->extract_separator_line) {
  13283.      XFWRITE(gp->extract_separator_line,
  13284.              strlen(gp->extract_separator_line));
  13285.      XFPUTC('\n');
  13286.      if (gp->extract_blank_before_separator) XFPUTC('\n');
  13287.    }
  13288.  }
  13289.  
  13290.  linelen = (ex == PRINT_IT ? 120 : 251);
  13291.  
  13292.  for (tp = thp->first_text_line;
  13293.       tp && !gp->extract_write_error;
  13294.       tp = tp->next) {
  13295.    if (tp->text_length == 0) {
  13296.      XFPUTC('\n');
  13297.    }
  13298.    else if (tp->text_length > 0) {
  13299.      if (gp->extract_tab_expanding) {
  13300.        cp = tp->tab_expanded_text;
  13301.        l  = tp->tab_expanded_text_length;
  13302.      }
  13303.      else {
  13304.        cp = tp->text;
  13305.        l  = tp->text_length;
  13306.      }
  13307.      for (; l>0 && !gp->extract_write_error; cp+=linelen, l-=linelen) {
  13308.        XFWRITE(cp,(l > linelen ? linelen : l));
  13309.        XFPUTC('\n');
  13310.      }
  13311.    }
  13312.  }
  13313.  
  13314.  if (!gp->extract_write_error && ferror(xfp))
  13315.     gp->extract_write_error = TRUE;
  13316.  
  13317.  if (!gp->extract_appending || !gp->extract_file) {
  13318.    switch (ex) {
  13319.      case EXTRACT_IT:   final = FALSE; break;
  13320.      case PRINT_IT:     final = TRUE;  break;
  13321.      default:           final = FALSE; break;
  13322.    }
  13323.    (ep->closer)(gp,ep,xfp,final);   /* Close the file */
  13324.    if (gp->extract_close_error) return FALSE;
  13325.  }
  13326.  
  13327.  if (!gp->extract_file) {
  13328.    if (gp->extract_write_error) {
  13329.      ERR2("An error occurred writing to %s.", ep->dsname);
  13330.      gp->extract_write_error = TRUE;
  13331.    }
  13332.    else switch (ex) {
  13333.      case EXTRACT_IT:
  13334.           WARN2("Current text extracted into %s.", ep->dsname);
  13335.           break;
  13336.      case PRINT_IT:
  13337.           WARN2("Current text printed to %s.", ep->dsname);
  13338.           break;
  13339.      case BOOKMARK_IT:
  13340.           WARN2("Item stored as bookmark in %s.", ep->dsname);
  13341.           break;
  13342.    }
  13343.  }
  13344.  if (gp->extract_write_error) return FALSE;
  13345.  else return TRUE;
  13346. }
  13347.  
  13348. ./ ADD NAME=GGSERVER
  13349. /*
  13350.  ***********************************************************************
  13351.  *                                                                     *
  13352.  * GOPHER server, based on the simple TCP/IP server from Shawn Hart at *
  13353.  * the University of Delaware.                                         *
  13354.  *                                                                     *
  13355.  ***********************************************************************
  13356.  *
  13357.  *  This server follows the GOPHER protocols defined by UMN.
  13358.  *  For more information, see the ANONYMOUS FTP site at
  13359.  *  BOOMBOX.MICRO.UMN.EDU.
  13360.  *
  13361.  ***********************************************************************
  13362.  *
  13363.  * November 1992 - parameters may be passed to the server:
  13364.  *
  13365.  * -d              run in debug mode
  13366.  *
  13367.  ***********************************************************************
  13368.  *
  13369.  * December 1992 - support for SNS/TCPAccess compilation
  13370.  *
  13371.  ***********************************************************************
  13372.  */
  13373.  
  13374. #pragma  csect(code,  "GG@ERVER")
  13375. #pragma  csect(static,"GG$ERVER")
  13376. #include "gg.h"                 /* All system file includes needed. */
  13377.  
  13378. /********************************************************************/
  13379.  
  13380. static int
  13381. tcpsetup(int          port,
  13382.          int          qlen,
  13383.          int          mtftasks,
  13384.          FILE        *debugfp)
  13385. {
  13386.  int                  tinitrc;             /* loop counter*/
  13387.  int                  sockfd;              /* loop counter*/
  13388.  int                  x;                   /* loop counter*/
  13389.  struct linger        l;                   /* linger for setsockopt */
  13390.  struct sockaddr_in   server;          /*server address information */
  13391.  
  13392.  /*    initialize the MTF  environment.                   */
  13393.  
  13394.  if (debugfp) {
  13395.    fprintf(debugfp,"tinit...\n");
  13396.    fflush(debugfp);
  13397.  }
  13398.  
  13399.  tinitrc = tinit("GGSTASK", mtftasks);
  13400.  
  13401.  if (tinitrc != MTF_OK) {
  13402.    GGMmtfer(tinitrc, "TINIT");
  13403.    return -1;
  13404.  }
  13405.  
  13406.  /*       open a TCP socket...                            */
  13407.  
  13408.  if (debugfp) {
  13409.    fprintf(debugfp,"socket...\n");
  13410.    fflush(debugfp);
  13411.  }
  13412.  
  13413.  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  13414.    REPORT_TCP_ERROR("SOCKET - ");
  13415.    return -1;
  13416.  };
  13417.  
  13418.  /*  set the linger option on so we wait for data to be sent... */
  13419.  
  13420.  l.l_onoff  =  1;
  13421.  l.l_linger =100;           /* wait 100 seconds before giving up */
  13422.  
  13423.  if (debugfp) {
  13424.    fprintf(debugfp,"setsockopt (%d, SO_LINGER)...\n",sockfd);
  13425.    fflush(debugfp);
  13426.  }
  13427.  
  13428.  if (setsockopt(sockfd,SOL_SOCKET,SO_LINGER,(char *)&l,sizeof(l))
  13429.      < 0) {
  13430.    REPORT_TCP_ERROR("SETSOCKOPT - ");
  13431.    return -1;
  13432.  }
  13433.  
  13434.  /*    now bind our local address so that the client can send to us */
  13435.  
  13436.  memset((char *)&server, 0, sizeof(server));
  13437.  server.sin_family           =   AF_INET;
  13438.  server.sin_addr.s_addr      =   INADDR_ANY;
  13439.  server.sin_port             =   htons(port);
  13440.  
  13441.  if (debugfp) {
  13442.    fprintf(debugfp,"bind (%d)...\n",sockfd);
  13443.    fflush(debugfp);
  13444.  }
  13445.  
  13446.  if (Bind(sockfd, &server, sizeof(server)) < 0) {
  13447.    REPORT_TCP_ERROR("BIND - ");
  13448.    return -1;
  13449.  }
  13450.  
  13451.  /*    now set length of the connection queue... */
  13452.  
  13453.  if (debugfp) {
  13454.    fprintf(debugfp,"listen (sockfd=%d, qlen=%d)...\n",sockfd,qlen);
  13455.    fflush(debugfp);
  13456.  }
  13457.  
  13458.  if (listen(sockfd,qlen) != 0) {
  13459.    REPORT_TCP_ERROR("LISTEN -");
  13460.    return -1;
  13461.  }
  13462.  
  13463.  return sockfd;
  13464.  
  13465. }
  13466.  
  13467.  
  13468. /********************************************************************/
  13469. /*
  13470. *   This routine waits for an exception on the socket.  When one
  13471. *   occurs (by a subtask's "TAKESOCKET"!) we'll close our (the main
  13472. *   task's) connection to it.
  13473. *
  13474. *               INPUT   s   pointer to socket descripter.
  13475. *               OUTPUT  rc  -1 = connection timed out...
  13476. *                            0 = an excption occured!
  13477. */
  13478. /********************************************************************/
  13479.  
  13480. #ifdef SNSTCPIP
  13481.  
  13482. static int
  13483. closesock(int              newsockfd,
  13484.           int              timeout,
  13485.           FILE            *debugfp)
  13486. {
  13487.  if (debugfp) {
  13488.    fprintf(debugfp,"close (%d)...\n",newsockfd);
  13489.    fflush(debugfp);
  13490.  }
  13491.  
  13492.  if (close(newsockfd) < 0) REPORT_TCP_ERROR("CLOSE -");
  13493.  return 0;
  13494. }
  13495.  
  13496. #else
  13497.  
  13498. static int
  13499. closesock(int              newsockfd,
  13500.           int              timeout,
  13501.           FILE            *debugfp)
  13502. {
  13503.  int                       temps;
  13504.  struct sockaddr           clientaddress;
  13505.  int                       addrlen;
  13506.  int                       maxfdpl;
  13507.  struct fd_set             readmask;
  13508.  struct fd_set             writmask;
  13509.  struct fd_set             exepmask;
  13510.  int                       rc;
  13511.  struct timeval            time;
  13512.  
  13513.  temps = newsockfd;
  13514.  time.tv_sec = timeout;
  13515.  time.tv_usec = 0;
  13516.  maxfdpl = temps + 1;
  13517.  
  13518.  FD_ZERO(&readmask);
  13519.  FD_ZERO(&writmask);
  13520.  FD_ZERO(&exepmask);
  13521.  FD_SET(temps, &exepmask);
  13522.  
  13523.  if (debugfp) {
  13524.    fprintf(debugfp,"select (maxfdpl=%d)...\n",maxfdpl);
  13525.    fflush(debugfp);
  13526.  }
  13527.  
  13528.  rc = select(maxfdpl, &readmask, &writmask, &exepmask, &time);
  13529.  
  13530.  if (rc < 0) {
  13531.    REPORT_TCP_ERROR("SELECT - ");
  13532.    return rc;
  13533.  }
  13534.  else {
  13535.    if (rc == 0) fprintf(stdout,"The GIVESOCKET timed out!\n");
  13536.  
  13537.    if (debugfp) {
  13538.      fprintf(debugfp,"close (%d)...\n",newsockfd);
  13539.      fflush(debugfp);
  13540.    }
  13541.  
  13542.    if (close(newsockfd) < 0) REPORT_TCP_ERROR("CLOSE -");
  13543.    return rc;
  13544.  }
  13545. }
  13546.  
  13547. #endif
  13548.  
  13549. /********************************************************************/
  13550. /*
  13551. *       This routine starts a subtask, passing control of a socket
  13552. *       to it.  It then waits for the subtask to take the socket and
  13553. *       then closes the socket.
  13554. *
  13555. *       INPUT: newsockfd - socket descriptor to give to subtask.
  13556. */
  13557. /********************************************************************/
  13558.  
  13559. static Bool
  13560. spawn(
  13561.       int           newsockfd,
  13562.       int           timeout,
  13563.  struct recvstruct *recvp,
  13564.       FILE         *debugfp)
  13565. {
  13566.  int                tschedrc;
  13567. #ifdef SNSTCPIP
  13568.  unsigned long      token;
  13569. #else
  13570.  struct clientid    clid;
  13571.  char               mysname[8];
  13572. #endif
  13573.  
  13574.  if (debugfp) {
  13575.    fprintf(debugfp,"getclientid...\n");
  13576.    fflush(debugfp);
  13577.  }
  13578.  
  13579. #ifdef SNSTCPIP
  13580.  
  13581.  token = closepass(newsockfd);
  13582.  if (debugfp) {
  13583.    fprintf(debugfp,"token = %X\n",token);
  13584.    fflush(debugfp);
  13585.  }
  13586.  
  13587. #else
  13588.  
  13589.  memset(&clid,0,sizeof(clid));
  13590.  if(getclientid(AF_INET,&clid) < 0) {
  13591.    REPORT_TCP_ERROR("GETCLIENTID");
  13592.    return FALSE;
  13593.  }
  13594.  
  13595.  if (debugfp) {
  13596.    fprintf(debugfp,"client name = %8.8s, subtaskname = %8.8s\n",
  13597.                    clid.name, clid.subtaskname);
  13598.    fflush(debugfp);
  13599.  }
  13600.  
  13601.  clid.domain = AF_INET;
  13602.  memcpy(mysname,clid.subtaskname,8);
  13603.  memcpy(clid.subtaskname,"        ",8);
  13604.  
  13605.  if (debugfp) {
  13606.    fprintf(debugfp,"givesocket (%d)...\n",newsockfd);
  13607.    fflush(debugfp);
  13608.  }
  13609.  
  13610.  if(givesocket(newsockfd,&clid) != 0) {
  13611.    REPORT_TCP_ERROR("GIVESOCKET");
  13612.    return FALSE;
  13613.  }
  13614.  memcpy(clid.subtaskname,mysname,8);
  13615.  
  13616.  if (debugfp) {
  13617.    fprintf(debugfp,"client name = %8.8s, subtaskname = %8.8s\n",
  13618.                    clid.name, clid.subtaskname);
  13619.    fflush(debugfp);
  13620.  }
  13621.  
  13622. #endif
  13623.  
  13624.  if (debugfp) {
  13625.    fprintf(debugfp,"tsched...\n");
  13626.    fflush(debugfp);
  13627.  }
  13628.  
  13629.  tschedrc = tsched(MTF_ANY,"GGSRECV",
  13630. #ifdef SNSTCPIP
  13631.                            token,
  13632. #else
  13633.                            newsockfd,
  13634.                            clid,
  13635. #endif
  13636.                            recvp,
  13637.                            (debugfp ? 1 : 0));
  13638.  
  13639.  if (debugfp) {
  13640.    fprintf(debugfp,"tsched completed...rc=%d\n",tschedrc);
  13641.    fflush(debugfp);
  13642.  }
  13643.  
  13644.  if (tschedrc != 0) {
  13645.    GGMmtfer(tschedrc,"TSCHED");
  13646.    return FALSE;
  13647.  }
  13648.  
  13649.  if (closesock(newsockfd,timeout,debugfp) < 0) {
  13650.    REPORT_TCP_ERROR("close socket");
  13651.    return FALSE;
  13652.  }
  13653.  
  13654.  return TRUE;
  13655.  
  13656. }
  13657.  
  13658. /******************************************************************/
  13659.  
  13660. static Bool
  13661. numparm(
  13662.         char *pvar,
  13663.         char *pval,
  13664.         int  *ivalp
  13665.        )
  13666. {
  13667.  if (*(pval + strspn(pval,"0123456789"))) {
  13668.    fprintf(stdout,"Non-numeric value given for %s: %s\n",
  13669.                   pvar, pval);
  13670.    return FALSE;
  13671.  }
  13672.  else {
  13673.   *ivalp = atoi(pval);
  13674.   return TRUE;
  13675.  }
  13676. }
  13677.  
  13678. /******************************************************************/
  13679.  
  13680. int
  13681. main(int            argc,
  13682.          char     **argv)
  13683. {
  13684.  int                trc;               /* return code */
  13685.  int                x;                 /* loop counter*/
  13686.  int                sockfd;            /* connection socket...*/
  13687.  int                newsockfd;         /* new connection socket...*/
  13688.  int                clientlen;         /* new connection socket...*/
  13689.  int                i;
  13690.  int                n;
  13691.  int                ival;
  13692.  char               cval;
  13693.  char              *p;
  13694.  char              *cp;
  13695.  FILE              *debugfp;
  13696.  FILE              *pfp;
  13697.  struct sockaddr_in client;            /* client address information */
  13698. #ifndef SNSTCPIP
  13699.  struct clientid    clid;              /* client info for givesocket */
  13700. #endif
  13701.  struct recvstruct  recvtemplate;
  13702.  int                mtftasks;
  13703.  int                port;
  13704.  int                qlength;
  13705.  int                timeout;
  13706.  char               telnet   [257];
  13707.  char               domain   [257];
  13708.  char                  pline    [RBUFSIZE];
  13709.  char                  pvar     [RBUFSIZE];
  13710.  char               pval     [RBUFSIZE];
  13711.  char               buffer   [255];      /* buffer for input/output*/
  13712.  
  13713. /******************************************************************/
  13714. /* Set parameter defaults.                                        */
  13715. /******************************************************************/
  13716.  
  13717.  mtftasks     = MTF_TASKS;
  13718.  port         = SERV_TCP_PORT;
  13719.  qlength      = TCP_QUEUE_LENGTH;
  13720.  timeout      = CONNECT_TIME_OUT;
  13721.  COPY(telnet,   TELNET_COMMAND_NAME);
  13722.  COPY(domain,   MY_DOMAIN_SUFFIX);
  13723.  
  13724. /******************************************************************/
  13725. /* Process server parameters.                                     */
  13726. /******************************************************************/
  13727.  
  13728.  debugfp = NULL;
  13729.  
  13730.  for (i = 1; i < argc; i++) {
  13731.    p = argv[i];
  13732.    if (*p == '-') {
  13733.      while (*++p) {
  13734.        switch (toupper(*p)) {
  13735.          case 'D':  debugfp = fopen(DEBUG_FILE,"w");
  13736.                     break;
  13737.          default:   break;
  13738.        }
  13739.      }
  13740.    }
  13741.  }
  13742.  
  13743. /******************************************************************/
  13744. /*         Read startup parameters from parameter file.           */
  13745. /******************************************************************/
  13746.  
  13747. /*
  13748.  * If dd:GGPARMS is present, then read parameters therefrom.
  13749.  * If not, then use defaults.  In any case, defaults will be
  13750.  * assigned where a corresponding parameter file line isn't found,
  13751.  *
  13752.  * Syntax of parameter file lines:
  13753.  *
  13754.  * VARIABLE value   comments
  13755.  *
  13756.  * e.g.
  13757.  *
  13758.  * MTFTASKS    8    the number of tasks
  13759.  *
  13760.  * Comments are indicated by "!" in col 1.
  13761.  *
  13762.  */
  13763.  
  13764.  pfp = fopen(PARAMETER_FILE,"r");
  13765.  if (!pfp) {
  13766.    perror(PARAMETER_FILE);
  13767.    fprintf(stdout,
  13768.            "No parameter file.  Using all installed defaults.\n");
  13769.    fflush(stderr);
  13770.  }
  13771.  else {
  13772.    for (;;) {
  13773.      fgets(pline, sizeof(pline), pfp);
  13774.      if (ferror(pfp)) {
  13775.        fprintf(stderr,"Error reading parameters from %s\n",
  13776.                       PARAMETER_FILE);
  13777.        fflush(stderr);
  13778.        break;
  13779.      }
  13780.      if (feof(pfp)) break;
  13781.      cp = pline;                     /* Start parameter scan       */
  13782.      if (*cp == '!') continue;       /* Skip comment               */
  13783.      *pvar = '\0';                   /* Clear parameter variable   */
  13784.      sscanf(cp,"%s %n",pvar,&n);     /* Get parameter, bump scan   */
  13785.      if (!*pvar) continue;           /* If nothing on line, skip   */
  13786.      uppercase_in_place(pvar);       /* Fold variable name         */
  13787.      cp += n;                        /* Bump to next word in file  */
  13788.      *pval = '\0';                   /* Clear parameter value      */
  13789.      sscanf(cp,"%s %n",pval,&n);     /* Get next word, bump scan   */
  13790.      if (!*pval) {
  13791.        fprintf(stdout,"Parameter error: value missing for %s\n",
  13792.                       pvar);
  13793.        continue;
  13794.      }
  13795.      fprintf(stderr,"Setting %s to '%s' (%d)\n",pvar,pval,ival);
  13796.      if      (EQUAL(pvar,"MTFTASKS" )) {
  13797.                                         if (numparm(pvar,pval,&ival))
  13798.                                            mtftasks = ival;
  13799.                                        }
  13800.      else if (EQUAL(pvar,"PORT"     )) {
  13801.                                         if (numparm(pvar,pval,&ival))
  13802.                                            port     = ival;
  13803.                                        }
  13804.      else if (EQUAL(pvar,"QLENGTH"  )) {
  13805.                                         if (numparm(pvar,pval,&ival))
  13806.                                            qlength  = ival;
  13807.                                        }
  13808.      else if (EQUAL(pvar,"TIMEOUT"  )) {
  13809.                                         if (numparm(pvar,pval,&ival))
  13810.                                            timeout  = ival;
  13811.                                        }
  13812.      else if (EQUAL(pvar,"TELNET"   )) {
  13813.                                         uppercase_in_place(pval);
  13814.                                         COPY(telnet,pval);
  13815.                                        }
  13816.      else if (EQUAL(pvar,"DOMAIN"   )) {
  13817.                                         uppercase_in_place(pval);
  13818.                                         COPY(domain,pval);
  13819.                                        }
  13820.      else {
  13821.        fprintf(stdout,"Unknown parameter, %s.  Skipping.\n",pvar);
  13822.      }
  13823.    }
  13824.    (void)fclose(pfp);
  13825.  }
  13826.  
  13827. /******************************************************************/
  13828. /*         display parameter values in effect                     */
  13829. /******************************************************************/
  13830.  
  13831.  /* Set defaults to pass to the subtask. */
  13832.  
  13833.  memset(&recvtemplate,0,sizeof(struct recvstruct));
  13834.  
  13835.  recvtemplate.myport       = port;
  13836.  recvtemplate.mytelnet     = telnet;
  13837.  recvtemplate.mydomain     = domain;
  13838.  
  13839.  fprintf(stdout,"Parameter values in effect:\n\n");
  13840.  fprintf(stdout,"MTFTASKS = %d\n", mtftasks);
  13841.  fprintf(stdout,"QLENGTH  = %d\n", qlength);
  13842.  fprintf(stdout,"TIMEOUT  = %d\n", timeout);
  13843.  fprintf(stdout,"PORT     = %d\n", recvtemplate.myport);
  13844.  fprintf(stdout,"TELNET   = %s\n", recvtemplate.mytelnet);
  13845.  fprintf(stdout,"DOMAIN   = %s\n", recvtemplate.mydomain);
  13846.  fprintf(stdout,"\n");
  13847.  
  13848.  fflush(stdout);
  13849.  
  13850. /******************************************************************/
  13851. /*         set up the connection to the socket...                 */
  13852. /******************************************************************/
  13853.  
  13854.  sockfd = tcpsetup(port,qlength,mtftasks,debugfp);
  13855.  if (sockfd < 0) {
  13856.    fprintf(stdout,"Could not set up the TCP/IP environment!\n");
  13857.    exit(16);
  13858.  }
  13859.  
  13860. /******************************************************************/
  13861. /*         Now loop, waiting for a connection request.            */
  13862. /******************************************************************/
  13863.  
  13864.  clientlen = sizeof(client);
  13865.  x = 0;
  13866.  for (;;) {
  13867.  
  13868.    if (debugfp) {
  13869.      fprintf(debugfp,"accept (%d)...\n",sockfd);
  13870.      fflush(debugfp);
  13871.    }
  13872.  
  13873.    if ((newsockfd=Accept(sockfd,&client,&clientlen)) == -1) {
  13874.      REPORT_TCP_ERROR("ACCEPT - ");
  13875.      exit(8);
  13876.    }
  13877.    if (debugfp) {
  13878.      fprintf(debugfp,"newsockfd=%d...\n",newsockfd);
  13879.      fflush(debugfp);
  13880.    }
  13881.  
  13882.    x++;
  13883.    if (!spawn(newsockfd,timeout,&recvtemplate,debugfp)) {
  13884.      fprintf(stdout,"spawn failed for socket %d\n",newsockfd);
  13885.      exit(8);
  13886.    }
  13887.    else {
  13888.      if (debugfp) {
  13889.        fprintf(debugfp,"spawn OK for socket %d\n",newsockfd);
  13890.        fflush(debugfp);
  13891.      }
  13892.    }
  13893.  }
  13894.  
  13895. /******************************************************************/
  13896. /*         Wait for all pending tasks to complete (should never   */
  13897. /*         run, since I haven't added PURGE support yet...)       */
  13898. /*         then shut down subtasks.                               */
  13899. /******************************************************************/
  13900.  
  13901.  if (debugfp) {
  13902.    fprintf(debugfp,"tsyncro...\n");
  13903.    fflush(debugfp);
  13904.  }
  13905.  
  13906.  trc = tsyncro(MTF_ALL);
  13907.  if (trc != 0) {
  13908.    GGMmtfer(trc,"TSYNCRO");
  13909.  }
  13910.  
  13911.  if (debugfp) {
  13912.    fprintf(debugfp,"tterm...\n");
  13913.    fflush(debugfp);
  13914.  }
  13915.  
  13916.  trc = tterm();
  13917.  if (trc != 4) {
  13918.    GGMmtfer(trc,"TTERM");
  13919.    exit(8);
  13920.  }
  13921.  
  13922.  if (debugfp) fclose(debugfp);
  13923.  
  13924.  exit(0);
  13925.  
  13926. }
  13927. ./ ADD NAME=GGSTASK
  13928.  
  13929.  /********************************************************************/
  13930.  /*                                                                  */
  13931.  /* GOPHER server due to Shawn Hart at the University of Delaware.   */
  13932.  /*                                                                  */
  13933.  /* This software is provided on an "AS IS" basis.  All warranties,  */
  13934.  /* including the implied warranties of merchantability and fitness, */
  13935.  /* are expressly denied.                                            */
  13936.  /*                                                                  */
  13937.  /* Provided this copyright notice is included, this software may    */
  13938.  /* be freely distributed and not offered for sale.                  */
  13939.  /*                                                                  */
  13940.  /* Changes or modifications may be made and used only by the maker  */
  13941.  /* of same, and not further distributed.  Such modifications should */
  13942.  /* be mailed to the author for consideration for addition to the    */
  13943.  /* software and incorporation in subsequent releases.               */
  13944.  /*                                                                  */
  13945.  /********************************************************************/
  13946.  
  13947. #pragma  csect(code,  "GGSTASK ")
  13948. #pragma  csect(static,"GG$TASK ")
  13949.  
  13950. #include "gg.h"
  13951.  
  13952. /*=================================================================*/
  13953.  
  13954. /*******************************************************************/
  13955. /*                                                                 */
  13956. /*    this is a debugging routine;  it looks at the status of a    */
  13957. /*    socket.                                                      */
  13958. /*******************************************************************/
  13959.  
  13960. static void
  13961. lookatsocket(int sockfd)
  13962. {
  13963.  int             rc;                       /* return code */
  13964.  int             length;                   /* length variable */
  13965.  int             option;
  13966.  int             x;
  13967.  struct linger   l;                        /* linger structure */
  13968.  char            buffer[RBUFSIZE];
  13969.  
  13970.  length = sizeof(l);
  13971.  if (Getsockopt(sockfd,SOL_SOCKET, SO_LINGER,&l,&length)==0) {
  13972.    printf("l_onoff=%d\n",l.l_onoff);
  13973.    printf("l_linger=%d\n",l.l_linger);
  13974.  }
  13975.  else REPORT_TCP_ERROR("GETSOCKOPT");
  13976.  
  13977.  length = sizeof(option);
  13978.  if (Getsockopt(sockfd,SOL_SOCKET, SO_ERROR,&option,&length)==0) {
  13979.    printf("so_error=%d\n",option);
  13980.  }
  13981.  else REPORT_TCP_ERROR("GETSOCKOPT");
  13982.  
  13983.  if (fcntl(sockfd,F_SETFL,FNDELAY)!=0) REPORT_TCP_ERROR("FCNTL");
  13984.  
  13985.  length = recv(sockfd,buffer,sizeof(buffer)-1,0);
  13986.  if (length == -1) {
  13987.    if (errno != EWOULDBLOCK) REPORT_TCP_ERROR("recv");
  13988.  }
  13989.  else {
  13990.    buffer[sizeof(buffer)-1] = 0;
  13991.    printf("buffer =%s\n",buffer);
  13992.    for (x=0;x<length;x++) printf("%x ",buffer[x]);
  13993.    printf("\n");
  13994.  }
  13995.  
  13996. }
  13997.  
  13998. /*******************************************************************/
  13999.  
  14000. /**************************************************************/
  14001. /*    this routine processes the data once a connection       */
  14002. /*    has been accepted.  It just takes the data sent by the  */
  14003. /*    client and prints it to sysprint, then sends it back    */
  14004. /*    to the client.                                          */
  14005. /*                                                            */
  14006. /*             INPUT:   newsockfd  - socket descriptor        */
  14007. /*                      clid       - takesocket structure...  */
  14008. /**************************************************************/
  14009.  
  14010. void
  14011. GGSrecv(
  14012. #ifdef SNSTCPIP
  14013.  unsigned long      token,
  14014. #else
  14015.  int                newsockfd,
  14016.  struct clientid    clid,
  14017. #endif
  14018.  struct recvstruct *recvtp,
  14019.  int                is_debug
  14020.        )
  14021. {
  14022.  struct recvstruct *R;
  14023.  struct hostent    *hostentp;
  14024.  char              *bufptr;   /* pointer into buffer strings         */
  14025.  char              *hp;
  14026.  char             **halias;
  14027.  int                retcode;  /* return code                         */
  14028.  int                len;      /* length of the buffer we're sent     */
  14029.  int                x;        /* loop counter                        */
  14030.  int                addrlen;  /* length of client address socket     */
  14031.  int                hostlen;
  14032.  int                domslen;
  14033.  struct sockaddr_in clientaddress; /* address of client              */
  14034.  struct recvstruct  r;
  14035.  time_t             timeval;
  14036.  struct tm         *tmp;
  14037.  char               outbuf[RBUFSIZE];  /* hold an output string */
  14038.  char               timestamp[20];
  14039.  
  14040.  /* Initialize recv struct with values passed from main task. */
  14041.  
  14042.  memcpy(&r, recvtp, sizeof(struct recvstruct));
  14043.  R = &r;
  14044.  
  14045. #ifdef SNSTCPIP
  14046.  
  14047.  if (is_debug) {
  14048.    fprintf(stdout,"openold (token=%X)...\n",token);
  14049.    fflush(stdout);
  14050.  }
  14051.  s0skcfg.exitfunc = NULL; /* Set exit address to NULL */
  14052.  R->sockfd = openold(token);
  14053.  if (is_debug) {
  14054.    fprintf(stdout,"sockfd from openold is %d\n", R->sockfd);
  14055.    fflush(stdout);
  14056.  }
  14057.  if(R->sockfd < 0) {
  14058.    REPORT_TCP_ERROR("OPENOLD");
  14059.    fflush(stderr);
  14060.    return;
  14061.  }
  14062.  
  14063. #else
  14064.  
  14065.  if (is_debug) {
  14066.    fprintf(stdout,"takesocket (newsockfd=%d)...\n",newsockfd);
  14067.    fprintf(stdout,"name is %8.8s, subtaskname is %8.8s\n",
  14068.                   clid.name,clid.subtaskname);
  14069.    fflush(stdout);
  14070.  }
  14071.  
  14072.  R->sockfd = takesocket(&clid,newsockfd);
  14073.  if (is_debug) {
  14074.    fprintf(stdout,"sockfd from takesocket is %d\n", R->sockfd);
  14075.    fflush(stdout);
  14076.  }
  14077.  if(R->sockfd < 0) {
  14078.    REPORT_TCP_ERROR("TAKESOCKET");
  14079.    return;
  14080.  }
  14081.  
  14082. #endif
  14083.  
  14084.  time(&timeval);
  14085.  tmp = localtime(&timeval);
  14086.  sprintf(timestamp,"%2.2d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d",
  14087.          tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_year,
  14088.          tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
  14089.  
  14090.  if (is_debug) {
  14091.    fprintf(stdout,"getpeername...\n");
  14092.    fflush(stdout);
  14093.  }
  14094.  
  14095.  addrlen = sizeof(clientaddress);
  14096.  if(Getpeername(R->sockfd,&clientaddress,&addrlen)!=0) {
  14097.    REPORT_TCP_ERROR("GETPEERNAME");
  14098.    printf("could not determine client address for socket %d\n",
  14099.           R->sockfd);
  14100.  }
  14101.  
  14102.  /* Try to get the name of the client host. */
  14103.  
  14104.  strcpy(R->hostname,"{UNKNOWN HOST NAME}");
  14105.  
  14106.  if (is_debug) {
  14107.    fprintf(stdout,"gethostbyaddr...\n");
  14108.    fflush(stdout);
  14109.  }
  14110.  
  14111.  hostentp = Gethostbyaddr(&clientaddress.sin_addr,
  14112.                           sizeof(clientaddress.sin_addr),
  14113.                           AF_INET);
  14114.  
  14115.  if (hostentp && hostentp->h_name) {
  14116.    memcpy(&R->clienthostent, hostentp, sizeof(struct hostent));
  14117.    strcpy(R->hostname,hostentp->h_name);
  14118.    uppercase_in_place(R->hostname);
  14119.  }
  14120.  
  14121.  strcpy(R->hosttest,R->hostname);
  14122.  
  14123.  hostlen = strlen(R->hosttest);
  14124.  domslen = strlen(R->mydomain);
  14125.  if (hostlen > domslen) {
  14126.    hp = R->hosttest + hostlen - domslen;
  14127.    if (!memcmp(hp, R->mydomain, domslen)) {
  14128.      *hp = '\0';
  14129.    }
  14130.  }
  14131.  
  14132.  printf("%s Connection from %s (%s, aka %s).  Socket %d\n",
  14133.         timestamp,
  14134.         inet_ntoa(clientaddress.sin_addr), R->hostname, R->hosttest,
  14135.         R->sockfd);
  14136.  
  14137.  /* This still doesn't do anything.
  14138.   *
  14139.   * if (hostentp && hostentp->h_name) {
  14140.   *   memcpy(&R->clienthostent, hostentp, sizeof(struct hostent));
  14141.   *   for (halias = R->clienthostent.h_aliases; *halias; halias++) {
  14142.   *     printf("  Host alias:'%s'\n",*halias);
  14143.   *   }
  14144.   * }
  14145.   */
  14146.  
  14147.  R->buffer[0] = '\0';
  14148.  bufptr = R->buffer;
  14149.  
  14150. /***********************/
  14151. /*  NOTE:  sometimes, if timing is right, RECV can return a 0 length */
  14152. /* record when a connection is closed by the client!!  below is a   */
  14153. /* hack to check for a 0 length record, and then terminate this     */
  14154. /* connection if we got one.                                        */
  14155. /***********************/
  14156.  
  14157. #define RECV_SIZE       (sizeof(R->buffer)-1)
  14158.  
  14159.  for (;;) {
  14160.  
  14161.    if (is_debug) {
  14162.      fprintf(stdout,"recv (sock=%d,size=%d)...\n",R->sockfd,RECV_SIZE);
  14163.      fflush(stdout);
  14164.    }
  14165.  
  14166.    if ((len=recv(R->sockfd,outbuf,RECV_SIZE,0)) <= 0) {
  14167.      REPORT_TCP_ERROR("RECV - ");
  14168.      printf("%s tcp error! len=%d\n",R->hostname, len);
  14169.      break;
  14170.    }
  14171.  
  14172.    *(outbuf+(len))=0;    /*make sure it's null terminated...*/
  14173.    /* printf("len=%d;",len); */
  14174.    ASCII_TO_EBCDIC(outbuf,len);
  14175.    if (strlen(R->buffer) + strlen(outbuf) >= sizeof(R->buffer)) {
  14176.      printf("\nError: More than %d bytes seen without CRLF\n",
  14177.             sizeof(R->buffer)-1);
  14178.      len = 0;
  14179.      break;
  14180.    }
  14181.    strcat(R->buffer,outbuf);
  14182.    bufptr=R->buffer+(strlen(R->buffer)-2);
  14183.    if (*bufptr == CARRIAGE_RETURN && *(bufptr+1) == LINE_FEED) break;
  14184.  }
  14185.  
  14186.  /* Note: no \n required, data line already has CRLF in it */
  14187.  fprintf(stderr,"%s %s Client data:%s",
  14188.                 timestamp, R->hostname, R->buffer);
  14189.  
  14190.  if (len < 0) return;
  14191.  else if (len == 0) {
  14192.    (void)GGMouts(R,
  14193.   "1Sorry, the GOPHER server couldn't hear you.  Try again.\t0\t0\t0");
  14194.  }
  14195.  else (void)GGMproc(R);
  14196.  
  14197.  (void)GGMouts(R,NULL);          /* send terminating dot */
  14198.  
  14199.  fflush(stdout);
  14200.  fflush(stderr);
  14201.  
  14202. #ifdef DEBUGMTF
  14203.  lookatsocket(R->sockfd);
  14204. #endif
  14205.  
  14206.  if (is_debug) {
  14207.    fprintf(stdout,"close (%d)...\n",R->sockfd);
  14208.    fflush(stdout);
  14209.  }
  14210.  
  14211.  if(close(R->sockfd)<0) REPORT_TCP_ERROR("CLOSE - ");
  14212.  
  14213. }
  14214. ./ ENDUP
  14215. ?!
  14216. //PANELS   EXEC MDLOAD,BS='6160',TRK1='5',TRK2='1',TO='PANELS'
  14217. //SYSIN    DD   DATA,DLM='?!'
  14218. ./ ADD NAME=GGM
  14219. )ATTR
  14220. /*                                                                   /*
  14221. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14222. /*                                                                   /*
  14223. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14224. /* including the implied warranties of merchantability and fitness,  /*
  14225. /* are expressly denied.                                             /*
  14226. /*                                                                   /*
  14227. /* Provided this copyright notice is included, this software may     /*
  14228. /* be freely distributed and not offered for sale.                   /*
  14229. /*                                                                   /*
  14230. /* Changes or modifications may be made and used only by the maker   /*
  14231. /* of same, and not further distributed.  Such modifications should  /*
  14232. /* be mailed to the author for consideration for addition to the     /*
  14233. /* software and incorporation in subsequent releases.                /*
  14234. /*                                                                   /*
  14235.  ^ TYPE(INPUT) INTENS(HIGH) COLOR(GREEN) CAPS(OFF)
  14236.  ! TYPE(TEXT)  INTENS(HIGH) COLOR(RED)
  14237. )BODY EXPAND(``)
  14238. %-`-`-  MVS Gopher Client -`-`-
  14239. %COMMAND ===>_ZCMD
  14240. +
  14241. %Gopher server host name+(or IP address) %===>_GGHOST
  14242. +
  14243. %Initial path%===>^GGPATH
  14244. %Port number %===>_GGPORT
  14245. +
  14246. +Note:  You may specify a dash%-+as the Gopher server host name if
  14247.         you want to use your own private Gopher data without making
  14248.         a connection to a server.  If you do, you must specify the
  14249.         name of your private Gopher menu in the initial path.
  14250.         This name must be UNQUOTED AND FULLY QUALIFIED.
  14251.         Alternatively, you may allocate your initial Gopher menu
  14252.         to file GGGOPHER.
  14253.  
  14254.         Any menu entries must also specify a dash in the host field;
  14255.         otherwise they will require server access, as usual.
  14256.  
  14257.         To use the REXX interface, you must allocate file GGEXEC to
  14258.         your library of Gopherable REXX execs.
  14259.  
  14260. +Press!END+key to leave this menu.
  14261. )INIT
  14262.  &ZCMD = &Z
  14263.  IF (&GGPORT = &Z) &GGPORT = 70
  14264. )PROC
  14265.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14266.  VER (&GGHOST,NB)
  14267.  VER (&GGPORT,NUM)
  14268.  VPUT (GGHOST GGPATH GGPORT) PROFILE
  14269. )END
  14270. ./ ADD NAME=GGMCSO
  14271. )ATTR
  14272. /*                                                                   /*
  14273. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14274. /*                                                                   /*
  14275. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14276. /* including the implied warranties of merchantability and fitness,  /*
  14277. /* are expressly denied.                                             /*
  14278. /*                                                                   /*
  14279. /* Provided this copyright notice is included, this software may     /*
  14280. /* be freely distributed and not offered for sale.                   /*
  14281. /*                                                                   /*
  14282. /* Changes or modifications may be made and used only by the maker   /*
  14283. /* of same, and not further distributed.  Such modifications should  /*
  14284. /* be mailed to the author for consideration for addition to the     /*
  14285. /* software and incorporation in subsequent releases.                /*
  14286. /*                                                                   /*
  14287.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14288.        @   TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14289. )BODY
  14290. +
  14291. %Command ===>^ZCMD
  14292. +
  14293. +Enter name to search for:
  14294. +
  14295. @FNAME1             +==>^FVALUE1
  14296. @FNAME2             +==>^FVALUE2
  14297. @FNAME3             +==>^FVALUE3
  14298. @FNAME4             +==>^FVALUE4
  14299. @FNAME5             +==>^FVALUE5
  14300. @FNAME6             +==>^FVALUE6
  14301. @FNAME7             +==>^FVALUE7
  14302. @FNAME8             +==>^FVALUE8
  14303. @FNAME9             +==>^FVALUE9
  14304. @FNAME10            +==>^FVALUE10
  14305. @FNAME11            +==>^FVALUE11
  14306. @FNAME12            +==>^FVALUE12
  14307. @FNAME13            +==>^FVALUE13
  14308. @FNAME14            +==>^FVALUE14
  14309.  
  14310. +Press%ENTER+to submit search request.
  14311. +Press%&END (END)+to cancel the request.
  14312. +
  14313. )INIT
  14314.  &ZWINTTL = 'CSO Nameserver User Name Search'
  14315.  &END = PFK(END)
  14316.  .CURSOR = FVALUE1
  14317. )PROC
  14318.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  14319.  VPUT (FVALUE1 FVALUE2 FVALUE3 FVALUE4 FVALUE5 FVALUE6 FVALUE7) PROFILE
  14320.  VPUT (FVALUE8 FVALUE9 FVALUE10 FVALUE11 FVALUE12) PROFILE
  14321.  VPUT (FVALUE13 FVALUE14) PROFILE
  14322. )END
  14323. ./ ADD NAME=GGMDIR
  14324. )ATTR
  14325. /*                                                                   /*
  14326. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14327. /*                                                                   /*
  14328. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14329. /* including the implied warranties of merchantability and fitness,  /*
  14330. /* are expressly denied.                                             /*
  14331. /*                                                                   /*
  14332. /* Provided this copyright notice is included, this software may     /*
  14333. /* be freely distributed and not offered for sale.                   /*
  14334. /*                                                                   /*
  14335. /* Changes or modifications may be made and used only by the maker   /*
  14336. /* of same, and not further distributed.  Such modifications should  /*
  14337. /* be mailed to the author for consideration for addition to the     /*
  14338. /* software and incorporation in subsequent releases.                /*
  14339. /*                                                                   /*
  14340.  ~ TYPE(INPUT) INTENS(HIGH)  CAPS(OFF) JUST(LEFT)
  14341.  ^ TYPE(INPUT) INTENS(HIGH)  CAPS(OFF) JUST(LEFT)
  14342.  ! TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(RIGHT) COLOR(YELLOW)
  14343.  # TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(RIGHT) COLOR(BLUE)
  14344.  @ TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(RIGHT) COLOR(PINK)
  14345.  ? TYPE(OUTPUT) INTENS(LOW)  CAPS(OFF) JUST(LEFT)  COLOR(TURQ) PAD('.')
  14346.  |  AREA(DYNAMIC) EXTEND(ON) SCROLL(ON)
  14347.  \  AREA(DYNAMIC) EXTEND(OFF) SCROLL(OFF)
  14348.  01 TYPE(DATAOUT) INTENS(LOW)
  14349.  02 TYPE(DATAOUT) INTENS(HIGH)
  14350.  03 TYPE(DATAIN)  INTENS(LOW)
  14351.  04 TYPE(DATAIN)  INTENS(HIGH)
  14352.  05 TYPE(DATAOUT) COLOR(GREEN)
  14353.  06 TYPE(DATAOUT) COLOR(PINK)
  14354.  07 TYPE(DATAOUT) COLOR(RED)
  14355.  08 TYPE(DATAOUT) COLOR(TURQ)
  14356.  09 TYPE(DATAOUT) COLOR(YELLOW)
  14357.  0A TYPE(DATAIN)  COLOR(BLUE)
  14358.  0B TYPE(DATAIN)  COLOR(PINK)
  14359.  0C TYPE(DATAIN)  COLOR(TURQ)
  14360.  0D TYPE(DATAIN)  COLOR(WHITE)
  14361.  0E TYPE(DATAIN)  COLOR(YELLOW)
  14362. )BODY EXPAND(``)
  14363. %&GGGHEAD
  14364. %COMMAND ===>~GGGCMD                                          %SCROLL ===>^GAMT+
  14365. +
  14366. +%S+Select%Q+Query%E+Extract%P+Print%B+Bookmark%I+Info
  14367.  -------------------------------------------------------------------------------
  14368. |GGGDYNA                                                                       |
  14369. )INIT
  14370.  IF (&GAMT = &Z) &GAMT = CSR
  14371.  IF (&GGGCSR ^= 0)
  14372.   .CURSOR = GGGDYNA
  14373.   .CSRPOS = &GGGCSR
  14374. )PROC
  14375.  &GGGLVL = LVLINE(GGGDYNA)
  14376.  VPUT (GAMT) PROFILE
  14377. )END
  14378. ./ ADD NAME=GGMLCONN
  14379. )ATTR
  14380. /*                                                                   /*
  14381. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14382. /*                                                                   /*
  14383. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14384. /* including the implied warranties of merchantability and fitness,  /*
  14385. /* are expressly denied.                                             /*
  14386. /*                                                                   /*
  14387. /* Provided this copyright notice is included, this software may     /*
  14388. /* be freely distributed and not offered for sale.                   /*
  14389. /*                                                                   /*
  14390. /* Changes or modifications may be made and used only by the maker   /*
  14391. /* of same, and not further distributed.  Such modifications should  /*
  14392. /* be mailed to the author for consideration for addition to the     /*
  14393. /* software and incorporation in subsequent releases.                /*
  14394. /*                                                                   /*
  14395.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  14396.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  14397.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  14398.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  14399.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  14400.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  14401.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  14402. )BODY EXPAND(``)
  14403. %-`-`-  MVS Gopher Server Connection -`-`-
  14404. +
  14405. +             Client name: &CLIENT
  14406. +
  14407. +
  14408. +             Connection is in progress for Gopher server at:
  14409.               &SERVER
  14410. +
  14411. +
  14412.                                  % Please wait.
  14413. +
  14414. +
  14415. )INIT
  14416. &CLIENT = '&GGCLIENT (&GGCLIEIP)'
  14417. &SERVER = '&GGSERVER (&GGSERVIP)'
  14418. )PROC
  14419. )END
  14420. ./ ADD NAME=GGMLDISC
  14421. )ATTR
  14422. /*                                                                   /*
  14423. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14424. /*                                                                   /*
  14425. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14426. /* including the implied warranties of merchantability and fitness,  /*
  14427. /* are expressly denied.                                             /*
  14428. /*                                                                   /*
  14429. /* Provided this copyright notice is included, this software may     /*
  14430. /* be freely distributed and not offered for sale.                   /*
  14431. /*                                                                   /*
  14432. /* Changes or modifications may be made and used only by the maker   /*
  14433. /* of same, and not further distributed.  Such modifications should  /*
  14434. /* be mailed to the author for consideration for addition to the     /*
  14435. /* software and incorporation in subsequent releases.                /*
  14436. /*                                                                   /*
  14437.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  14438.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  14439.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  14440.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  14441.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  14442.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  14443.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  14444. )BODY EXPAND(``)
  14445. %-`-`-  MVS Gopher Server Connection -`-`-
  14446. +
  14447. +
  14448. +         Disconnection is in progress from the Gopher server at:
  14449.           &GGSOLDER (&GGSOLDIP)
  14450. +
  14451. +
  14452.                                  % Please wait.
  14453. +
  14454. +
  14455. )INIT
  14456. )PROC
  14457. )END
  14458. ./ ADD NAME=GGMLEXN2
  14459. )ATTR
  14460. /*                                                                   /*
  14461. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14462. /*                                                                   /*
  14463. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14464. /* including the implied warranties of merchantability and fitness,  /*
  14465. /* are expressly denied.                                             /*
  14466. /*                                                                   /*
  14467. /* Provided this copyright notice is included, this software may     /*
  14468. /* be freely distributed and not offered for sale.                   /*
  14469. /*                                                                   /*
  14470. /* Changes or modifications may be made and used only by the maker   /*
  14471. /* of same, and not further distributed.  Such modifications should  /*
  14472. /* be mailed to the author for consideration for addition to the     /*
  14473. /* software and incorporation in subsequent releases.                /*
  14474. /*                                                                   /*
  14475.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  14476.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  14477.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  14478.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  14479.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  14480.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  14481. )BODY EXPAND(``)
  14482. %-`-`-  MVS Gopher Server Connection -`-`-
  14483. +
  14484. +Description: &GGTSUBJ
  14485. +
  14486. +Extracting to: &GGEXDSN
  14487. +&MEMSTUFF
  14488. +
  14489.                                  % Please wait.
  14490. +
  14491. )INIT
  14492.  IF (&GGEXMEM = &Z) &MEMSTUFF = &Z
  14493.  ELSE               &MEMSTUFF = 'Member: &GGEXMEM'
  14494. )PROC
  14495. )END
  14496. ./ ADD NAME=GGMLPRN2
  14497. )ATTR
  14498. /*                                                                   /*
  14499. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  14500. /*                                                                   /*
  14501. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14502. /* including the implied warranties of merchantability and fitness,  /*
  14503. /* are expressly denied.                                             /*
  14504. /*                                                                   /*
  14505. /* Provided this copyright notice is included, this software may     /*
  14506. /* be freely distributed and not offered for sale.                   /*
  14507. /*                                                                   /*
  14508. /* Changes or modifications may be made and used only by the maker   /*
  14509. /* of same, and not further distributed.  Such modifications should  /*
  14510. /* be mailed to the author for consideration for addition to the     /*
  14511. /* software and incorporation in subsequent releases.                /*
  14512. /*                                                                   /*
  14513.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  14514.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  14515.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  14516.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  14517.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  14518.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  14519. )BODY EXPAND(``)
  14520. %-`-`-  MVS Gopher Server Connection -`-`-
  14521. +
  14522. +Description: &GGTSUBJ
  14523. +
  14524. +Printing to SYSOUT class: &GGEXSCL
  14525. +&MEMSTUFF
  14526. +
  14527.                                  % Please wait.
  14528. +
  14529. )INIT
  14530.  IF (&GGEXMEM = &Z) &MEMSTUFF = &Z
  14531.  ELSE               &MEMSTUFF = 'Member: &GGEXMEM'
  14532. )PROC
  14533. )END
  14534. ./ ADD NAME=GGMLSOCK
  14535. )ATTR
  14536. /*                                                                   /*
  14537. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  14538. /*                                                                   /*
  14539. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14540. /* including the implied warranties of merchantability and fitness,  /*
  14541. /* are expressly denied.                                             /*
  14542. /*                                                                   /*
  14543. /* Provided this copyright notice is included, this software may     /*
  14544. /* be freely distributed and not offered for sale.                   /*
  14545. /*                                                                   /*
  14546. /* Changes or modifications may be made and used only by the maker   /*
  14547. /* of same, and not further distributed.  Such modifications should  /*
  14548. /* be mailed to the author for consideration for addition to the     /*
  14549. /* software and incorporation in subsequent releases.                /*
  14550. /*                                                                   /*
  14551.  ^ TYPE(TEXT) INTENS(HIGH) COLOR(BLUE) HILITE(REVERSE)
  14552.  @ TYPE(TEXT) INTENS(HIGH) COLOR(PINK)
  14553.  # TYPE(TEXT) INTENS(LOW)  COLOR(TURQ)
  14554.  \ TYPE(TEXT) INTENS(HIGH) COLOR(YELLOW)
  14555.  ! TYPE(TEXT) INTENS(HIGH) COLOR(RED)
  14556.  $ TYPE(TEXT) INTENS(LOW)  COLOR(GREEN)
  14557.  ~ TYPE(TEXT) INTENS(HIGH) COLOR(WHITE)
  14558. )BODY EXPAND(``)
  14559. %-`-`-  MVS Gopher Server Connection -`-`-
  14560. +
  14561. +             Client:  &CLIENT
  14562. +
  14563. +             Connection successful.
  14564. +
  14565. +             Retrieving data from Gopher server at:
  14566.               &SERVER
  14567. +
  14568. +
  14569.                                  % Please wait.
  14570. +
  14571. +
  14572. )INIT
  14573. &CLIENT = '&GGCLIENT (&GGCLIEIP)'
  14574. &SERVER = '&GGSERVER (&GGSERVIP)'
  14575. )PROC
  14576. )END
  14577. ./ ADD NAME=GGMOPT1
  14578. )ATTR
  14579. /*                                                                   /*
  14580. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14581. /*                                                                   /*
  14582. /* SAS enhancements copyright (c) 1992 SAS Institute, Inc.           /*
  14583. /*                                                                   /*
  14584. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14585. /* including the implied warranties of merchantability and fitness,  /*
  14586. /* are expressly denied.                                             /*
  14587. /*                                                                   /*
  14588. /* Provided this copyright notice is included, this software may     /*
  14589. /* be freely distributed and not offered for sale.                   /*
  14590. /*                                                                   /*
  14591. /* Changes or modifications may be made and used only by the maker   /*
  14592. /* of same, and not further distributed.  Such modifications should  /*
  14593. /* be mailed to the author for consideration for addition to the     /*
  14594. /* software and incorporation in subsequent releases.                /*
  14595. /*                                                                   /*
  14596. )BODY EXPAND(``)
  14597. %-`-`- GOPHER - Directory Viewing Options -`-`-
  14598. %Command ===>_ZCMD
  14599. +
  14600. +Scroll last selected menu item to top? (YES/NO)%==>_Z  +
  14601. +Put cursor at last selected menu item? (YES/NO)%==>_Z  +
  14602.  
  14603.  
  14604. +Press%ENTER+to change options.  Press%&END+(or type%END+command) when done.
  14605. )INIT
  14606.  .ZVARS  = '(GGSCROLL GGCURSOR)'
  14607.  .CURSOR = ZCMD
  14608.  &END = PFK(END)
  14609.  &ZCMD = &Z
  14610.  VGET (GGSCROLL GGCURSOR) PROFILE
  14611.  &GGSCROLL = TRANS(TRUNC(&GGSCROLL,1)  Y,YES N,NO *,YES)
  14612.  &GGCURSOR = TRANS(TRUNC(&GGCURSOR,1)  Y,YES N,NO *,NO )
  14613. )PROC
  14614.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14615.  IF (.RESP = ENTER)
  14616.   &GGSCROLL = TRUNC(&GGSCROLL,1)
  14617.   &GGCURSOR = TRUNC(&GGCURSOR,1)
  14618.   VER(&GGSCROLL,NB,LIST,Y,N)
  14619.   VER(&GGCURSOR,NB,LIST,Y,N)
  14620.  VPUT (GGSCROLL GGCURSOR) PROFILE
  14621. )END
  14622. ./ ADD NAME=GGMOPT2
  14623. )ATTR
  14624. /*                                                                   /*
  14625. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14626. /*                                                                   /*
  14627. /* SAS enhancements copyright (c) 1992 SAS Institute, Inc.           /*
  14628. /*                                                                   /*
  14629. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14630. /* including the implied warranties of merchantability and fitness,  /*
  14631. /* are expressly denied.                                             /*
  14632. /*                                                                   /*
  14633. /* Provided this copyright notice is included, this software may     /*
  14634. /* be freely distributed and not offered for sale.                   /*
  14635. /*                                                                   /*
  14636. /* Changes or modifications may be made and used only by the maker   /*
  14637. /* of same, and not further distributed.  Such modifications should  /*
  14638. /* be mailed to the author for consideration for addition to the     /*
  14639. /* software and incorporation in subsequent releases.                /*
  14640. /*                                                                   /*
  14641. )BODY EXPAND(``)
  14642. %-`-`- GOPHER - Miscellaneous Options -`-`-
  14643. %Command ===>_ZCMD
  14644. +
  14645. %EXTRACT prompting options:
  14646.  
  14647. +Warning panel before writing over an existing dataset?%==>_Z  +
  14648. +Warning panel before appending to an existing dataset?%==>_Z  +
  14649.  
  14650.  
  14651. +Press%ENTER+to change options.  Press%&END+(or type%END+command) when done.
  14652. )INIT
  14653.  .ZVARS  = '(GGEXTPOW GGEXTPAP)'
  14654.  .CURSOR = ZCMD
  14655.  &END = PFK(END)
  14656.  &ZCMD = &Z
  14657.  VGET (GGEXTPOW GGEXTPAP) PROFILE
  14658.  &GGEXTPOW = TRANS(TRUNC(&GGEXTPOW,1) Y,YES N,NO *,YES)
  14659.  &GGEXTPAP = TRANS(TRUNC(&GGEXTPAP,1) Y,YES N,NO *,YES)
  14660. )PROC
  14661.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14662.  IF (.RESP = ENTER)
  14663.   &GGEXTPOW = TRUNC(&GGEXTPOW,1)
  14664.   &GGEXTPAP = TRUNC(&GGEXTPAP,1)
  14665.   VER(&GGEXTPOW,NB,LIST,Y,N)
  14666.   VER(&GGEXTPAP,NB,LIST,Y,N)
  14667.  VPUT (GGEXTPOW GGEXTPAP) PROFILE
  14668. )END
  14669. ./ ADD NAME=GGMPBMDS
  14670. )ATTR
  14671. /*                                                                   /*
  14672. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14673. /*                                                                   /*
  14674. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14675. /* including the implied warranties of merchantability and fitness,  /*
  14676. /* are expressly denied.                                             /*
  14677. /*                                                                   /*
  14678. /* Provided this copyright notice is included, this software may     /*
  14679. /* be freely distributed and not offered for sale.                   /*
  14680. /*                                                                   /*
  14681. /* Changes or modifications may be made and used only by the maker   /*
  14682. /* of same, and not further distributed.  Such modifications should  /*
  14683. /* be mailed to the author for consideration for addition to the     /*
  14684. /* software and incorporation in subsequent releases.                /*
  14685. /*                                                                   /*
  14686.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14687. )BODY WINDOW(77,10)
  14688. +
  14689. %Command ===>^ZCMD
  14690. +
  14691. %&SUBJECT
  14692. +
  14693. +Bookmark data set ===>_GGBMDSN
  14694.  
  14695. +(Note: Data set must be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  14696.  
  14697. +Press%&END (END)+to cancel the bookmark request.
  14698. )INIT
  14699.  .CURSOR = GGBMDSN
  14700.  &ZWINTTL = 'Append bookmark'
  14701.  &SUBJECT = '&GGTSUBJ'
  14702.  &END = PFK(END)
  14703.  &ZCMD = &Z
  14704.  VGET (GGBMDSN) PROFILE
  14705.  IF (&GGBMDSN = &Z) &GGBMDSN = 'GOPHER.BOOKMARK'
  14706. )PROC
  14707.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14708.  VER(&GGBMDSN,NB,DSNAME)
  14709.  VPUT (GGBMDSN) PROFILE
  14710. )END
  14711. ./ ADD NAME=GGMPCSO
  14712. )ATTR
  14713. /*                                                                   /*
  14714. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14715. /*                                                                   /*
  14716. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14717. /* including the implied warranties of merchantability and fitness,  /*
  14718. /* are expressly denied.                                             /*
  14719. /*                                                                   /*
  14720. /* Provided this copyright notice is included, this software may     /*
  14721. /* be freely distributed and not offered for sale.                   /*
  14722. /*                                                                   /*
  14723. /* Changes or modifications may be made and used only by the maker   /*
  14724. /* of same, and not further distributed.  Such modifications should  /*
  14725. /* be mailed to the author for consideration for addition to the     /*
  14726. /* software and incorporation in subsequent releases.                /*
  14727. /*                                                                   /*
  14728.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14729. )BODY WINDOW(58,10)
  14730. +
  14731. %Command ===>^ZCMD
  14732. +
  14733. +Enter name to search for:
  14734. +
  14735. %===>^GGCSOQ
  14736.  
  14737. +Press%ENTER+to submit search request.
  14738. +Press%&END (END)+to cancel the request.
  14739. +
  14740. )INIT
  14741.  &ZWINTTL = 'CSO Nameserver User Name Search'
  14742.  &END = PFK(END)
  14743.  .CURSOR = GGCSOQ
  14744. )PROC
  14745.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  14746.  VER (&GGCSOQ,NB)
  14747.  VPUT (GGCSOQ) PROFILE
  14748. )END
  14749. ./ ADD NAME=GGMPDBM
  14750. )ATTR
  14751. /*                                                                   /*
  14752. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14753. /*                                                                   /*
  14754. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14755. /* including the implied warranties of merchantability and fitness,  /*
  14756. /* are expressly denied.                                             /*
  14757. /*                                                                   /*
  14758. /* Provided this copyright notice is included, this software may     /*
  14759. /* be freely distributed and not offered for sale.                   /*
  14760. /*                                                                   /*
  14761. /* Changes or modifications may be made and used only by the maker   /*
  14762. /* of same, and not further distributed.  Such modifications should  /*
  14763. /* be mailed to the author for consideration for addition to the     /*
  14764. /* software and incorporation in subsequent releases.                /*
  14765. /*                                                                   /*
  14766.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14767. )BODY WINDOW(58,13)
  14768. +
  14769. %Command ===>^ZCMD
  14770. +
  14771. +Remove bookmark from data set &GGMDBMDS:
  14772. +
  14773. %&GGMDBMSU
  14774. +
  14775. +Press%ENTER+to update &GGMDBMDS.
  14776. +Press%&END (END)+to cancel the request.
  14777. +
  14778. )INIT
  14779.  .ALARM = YES
  14780.  &ZWINTTL = 'Delete Bookmark'
  14781.  &END = PFK(END)
  14782. )PROC
  14783.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14784. )END
  14785. ./ ADD NAME=GGMPEXDS
  14786. )ATTR
  14787. /*                                                                   /*
  14788. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14789. /*                                                                   /*
  14790. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14791. /* including the implied warranties of merchantability and fitness,  /*
  14792. /* are expressly denied.                                             /*
  14793. /*                                                                   /*
  14794. /* Provided this copyright notice is included, this software may     /*
  14795. /* be freely distributed and not offered for sale.                   /*
  14796. /*                                                                   /*
  14797. /* Changes or modifications may be made and used only by the maker   /*
  14798. /* of same, and not further distributed.  Such modifications should  /*
  14799. /* be mailed to the author for consideration for addition to the     /*
  14800. /* software and incorporation in subsequent releases.                /*
  14801. /*                                                                   /*
  14802.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14803. )BODY WINDOW(77,16)
  14804. +
  14805. %Command ===>^ZCMD
  14806. +
  14807. %&SUBJECT
  14808. +
  14809. +Save to data set ===>_GGEXDSN
  14810. +Expand tab characters?       ===>_Z  +
  14811.  
  14812. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  14813.  
  14814. +Append to end of data set?   ===>_Z  +
  14815. +Blank line after separator?  ===>_Z  +
  14816. +Separator line between items (append mode only...blank for none):
  14817. +>^Z                                                                       +<
  14818.  
  14819. +Press%&END (END)+to cancel the extract request.
  14820. )INIT
  14821.  .ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
  14822.  .CURSOR = GGEXDSN
  14823.  &ZWINTTL = 'Extract text'
  14824.  &SUBJECT = '&GGTSUBJ'
  14825.  &END = PFK(END)
  14826.  &ZCMD = &Z
  14827.  VGET (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  14828.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  14829.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  14830.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  14831. )PROC
  14832.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14833.  VER(&GGEXDSN,NB,DSNAME)
  14834.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  14835.  VER(&GGEXTAB,NB,LIST,Y,N)
  14836.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  14837.  VER(&GGEXAPP,NB,LIST,Y,N)
  14838.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  14839.  VER(&GGEXBLK,NB,LIST,Y,N)
  14840.  VPUT (GGEXDSN GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  14841. )END
  14842. ./ ADD NAME=GGMPEXNG
  14843. )ATTR
  14844. /*                                                                   /*
  14845. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14846. /*                                                                   /*
  14847. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14848. /* including the implied warranties of merchantability and fitness,  /*
  14849. /* are expressly denied.                                             /*
  14850. /*                                                                   /*
  14851. /* Provided this copyright notice is included, this software may     /*
  14852. /* be freely distributed and not offered for sale.                   /*
  14853. /*                                                                   /*
  14854. /* Changes or modifications may be made and used only by the maker   /*
  14855. /* of same, and not further distributed.  Such modifications should  /*
  14856. /* be mailed to the author for consideration for addition to the     /*
  14857. /* software and incorporation in subsequent releases.                /*
  14858. /*                                                                   /*
  14859.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14860. )BODY WINDOW(77,14)
  14861. +
  14862. %Command ===>^ZCMD
  14863. +
  14864. +Save to data set ===>_GGEXDSN
  14865.  
  14866. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  14867.  
  14868. +Append to end of data set?   ===>_Z  +
  14869. +Blank line after separator?  ===>_Z  +
  14870. +Separator line between items (append mode only...blank for none):
  14871. +>^Z                                                                       +<
  14872.  
  14873. +Press%&END (END)+to cancel the extract request.
  14874. )INIT
  14875.  .ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
  14876.  .CURSOR = GGEXDSN
  14877.  &ZWINTTL = 'Extract item listing'
  14878.  &END = PFK(END)
  14879.  &ZCMD = &Z
  14880.  VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  14881.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  14882.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  14883. )PROC
  14884.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14885.  VER(&GGEXDSN,NB,DSNAME)
  14886.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  14887.  VER(&GGEXAPP,NB,LIST,Y,N)
  14888.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  14889.  VER(&GGEXBLK,NB,LIST,Y,N)
  14890.  VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  14891. )END
  14892. ./ ADD NAME=GGMPEXNP
  14893. )ATTR
  14894. /*                                                                   /*
  14895. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14896. /*                                                                   /*
  14897. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14898. /* including the implied warranties of merchantability and fitness,  /*
  14899. /* are expressly denied.                                             /*
  14900. /*                                                                   /*
  14901. /* Provided this copyright notice is included, this software may     /*
  14902. /* be freely distributed and not offered for sale.                   /*
  14903. /*                                                                   /*
  14904. /* Changes or modifications may be made and used only by the maker   /*
  14905. /* of same, and not further distributed.  Such modifications should  /*
  14906. /* be mailed to the author for consideration for addition to the     /*
  14907. /* software and incorporation in subsequent releases.                /*
  14908. /*                                                                   /*
  14909.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14910. )BODY EXPAND(``) WINDOW(77,14)
  14911. +
  14912. %Command ===>^ZCMD
  14913. +
  14914. +Data set name%===>_GGEXPDS
  14915. +Member prefix%===>_GGEXPMP + (item number appended - default is%#+)
  14916.  
  14917. +Note: The dataset must be a PDS (old or new) with RECFM=VB and LRECL=259.
  14918.  
  14919. +Expand tab characters?      %===>_Z  +
  14920.  
  14921. +From item number%===>_GGEXAN1         + (blank for first item in table)
  14922. +To   item number%===>_GGEXAN2         + (blank for last item in table)
  14923.  
  14924. +Press%&END (END)+to cancel the extract request.
  14925. )INIT
  14926.  .ZVARS = '(GGEXTAB)'
  14927.  .CURSOR = ZCMD
  14928.  &ZWINTTL = 'Log text of items to PDS members'
  14929.  &END = PFK(END)
  14930.  &ZCMD = &Z
  14931.  VGET (GGEXPDS GGEXPMP GGEXTAB) PROFILE
  14932.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  14933.  IF (&GGEXPMP = &Z) &GGEXPMP = '#'
  14934.  &GGEXAN1 = &Z
  14935.  &GGEXAN2 = &Z
  14936. )PROC
  14937.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  14938.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  14939.  VER(&GGEXTAB,NB,LIST,Y,N)
  14940.  VER(&GGEXPDS,NB,DSNAME)
  14941.  &TEMP1 = TRUNC(&GGEXPDS,1)
  14942.  &TEMP2 = .TRAIL
  14943.  IF (&TEMP1 = '''')
  14944.   &GGEXDSN = TRUNC(&TEMP2,'''')
  14945.  ELSE
  14946.   &GGEXDSN = '&ZPREFIX..&GGEXPDS'
  14947.   VER(&GGEXPMP,NB,NAME)
  14948.  VER(&GGEXAN1,NUM)
  14949.  VER(&GGEXAN2,NUM)
  14950.  VPUT (GGEXPDS GGEXPMP GGEXTAB) PROFILE
  14951. )END
  14952. ./ ADD NAME=GGMPEXNS
  14953. )ATTR
  14954. /*                                                                   /*
  14955. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  14956. /*                                                                   /*
  14957. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  14958. /* including the implied warranties of merchantability and fitness,  /*
  14959. /* are expressly denied.                                             /*
  14960. /*                                                                   /*
  14961. /* Provided this copyright notice is included, this software may     /*
  14962. /* be freely distributed and not offered for sale.                   /*
  14963. /*                                                                   /*
  14964. /* Changes or modifications may be made and used only by the maker   /*
  14965. /* of same, and not further distributed.  Such modifications should  /*
  14966. /* be mailed to the author for consideration for addition to the     /*
  14967. /* software and incorporation in subsequent releases.                /*
  14968. /*                                                                   /*
  14969.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  14970. )BODY EXPAND(``) WINDOW(77,17)
  14971. +
  14972. %Command ===>^ZCMD
  14973. +
  14974. +Data set name%===>_GGEXSEQ
  14975. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  14976. +
  14977. +Expand tab characters?      %===>_Z  +
  14978. +
  14979. +Append to end of data set?  %===>_Z  +
  14980. +Blank line after separator? %===>_Z  +
  14981. +Separator line before each item (leave blank for none):
  14982. +>^Z                                                                       +<
  14983.  
  14984. +From item number%===>_GGEXAN1         + (blank for first item in table)
  14985. +To   item number%===>_GGEXAN2         + (blank for last item in table)
  14986.  
  14987. +Press%&END (END)+to cancel the extract request.
  14988. )INIT
  14989.  .ZVARS = '(GGEXTAB GGEXAPP GGEXBLK GGEXSEP)'
  14990.  .CURSOR = ZCMD
  14991.  &ZWINTTL = 'Log text of items to sequential file'
  14992.  &END = PFK(END)
  14993.  &ZCMD = &Z
  14994.  VGET (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  14995.  &GGEXTAB = TRANS(&GGEXTAB Y,YES N,NO ' ',NO)
  14996.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  14997.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  14998.  &GGEXAN1 = &Z
  14999.  &GGEXAN2 = &Z
  15000. )PROC
  15001.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  15002.  VER(&GGEXSEQ,NB,DSNAME)
  15003.  &GGEXDSN = &GGEXSEQ
  15004.  &GGEXTAB = TRUNC(&GGEXTAB,1)
  15005.  VER(&GGEXTAB,NB,LIST,Y,N)
  15006.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  15007.  VER(&GGEXAPP,NB,LIST,Y,N)
  15008.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  15009.  VER(&GGEXBLK,NB,LIST,Y,N)
  15010.  VER(&GGEXAN1,NUM)
  15011.  VER(&GGEXAN2,NUM)
  15012.  VPUT (GGEXSEQ GGEXTAB GGEXAPP GGEXBLK GGEXSEP) PROFILE
  15013. )END
  15014. ./ ADD NAME=GGMPEXNT
  15015. )ATTR
  15016. /*                                                                   /*
  15017. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15018. /*                                                                   /*
  15019. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15020. /* including the implied warranties of merchantability and fitness,  /*
  15021. /* are expressly denied.                                             /*
  15022. /*                                                                   /*
  15023. /* Provided this copyright notice is included, this software may     /*
  15024. /* be freely distributed and not offered for sale.                   /*
  15025. /*                                                                   /*
  15026. /* Changes or modifications may be made and used only by the maker   /*
  15027. /* of same, and not further distributed.  Such modifications should  /*
  15028. /* be mailed to the author for consideration for addition to the     /*
  15029. /* software and incorporation in subsequent releases.                /*
  15030. /*                                                                   /*
  15031.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15032. )BODY WINDOW(77,10)
  15033. +
  15034. %Command ===>^ZCMD
  15035. +
  15036. +Move cursor to choice (or type%S+next to choice) and press%ENTER+to select:
  15037. +
  15038. _A%1+- List%titles+of items in table
  15039. _B%2+- Log %text  +of items to%sequential file+
  15040. _C%3+- Log %text  +of items to%members of PDS+
  15041. +
  15042. +Press%&END (END)+to cancel the extract request.
  15043. )INIT
  15044.  .CURSOR = ZCMD
  15045.  &ZWINTTL = 'Extract Gopher items - titles or text'
  15046.  &END = PFK(END)
  15047.  &ZCMD = &Z
  15048.  &A = &Z
  15049.  &B = &Z
  15050.  &C = &Z
  15051. )PROC
  15052.  VER(&ZCMD,LIST,1,2,3)
  15053.  IF (&ZCMD ^= &Z)
  15054.   &GGCHOICE = TRANS(&ZCMD 1 1 2 2 3 3 * ?)
  15055.  ELSE
  15056.   &TEMP = '&A/&B/&C'
  15057.   IF (&TEMP = '//')
  15058.    &GGCHOICE = TRANS(.CURSOR A 1 B 2 C 3 * ?)
  15059.   ELSE
  15060.    &GGCHOICE = TRANS(&TEMP  'S//' 1
  15061.                             '1//' 1
  15062.                             '/S/' 2
  15063.                             '/2/' 2
  15064.                             '//S' 3
  15065.                             '//3' 3
  15066.                                * ?
  15067.                    )
  15068. )END
  15069. ./ ADD NAME=GGMPEXN1
  15070. )ATTR
  15071. /*                                                                   /*
  15072. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15073. /*                                                                   /*
  15074. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15075. /* including the implied warranties of merchantability and fitness,  /*
  15076. /* are expressly denied.                                             /*
  15077. /*                                                                   /*
  15078. /* Provided this copyright notice is included, this software may     /*
  15079. /* be freely distributed and not offered for sale.                   /*
  15080. /*                                                                   /*
  15081. /* Changes or modifications may be made and used only by the maker   /*
  15082. /* of same, and not further distributed.  Such modifications should  /*
  15083. /* be mailed to the author for consideration for addition to the     /*
  15084. /* software and incorporation in subsequent releases.                /*
  15085. /*                                                                   /*
  15086.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15087. )BODY WINDOW(77,14)
  15088. +
  15089. %Command ===>^ZCMD
  15090. +
  15091. +Save to data set ===>_GGEXDSN
  15092.  
  15093. +(Note: Data set will be RECFM=VB, LRECL=259, BLKSIZE=6233.)
  15094.  
  15095. +Append to end of data set?   ===>_Z  +
  15096. +Blank line after separator?  ===>_Z  +
  15097. +Separator line between items (append mode only...blank for none):
  15098. +>^Z                                                                       +<
  15099.  
  15100. +Press%&END (END)+to cancel the extract request.
  15101. )INIT
  15102.  .ZVARS = '(GGEXAPP GGEXBLK GGEXSEP)'
  15103.  .CURSOR = GGEXDSN
  15104.  &ZWINTTL = 'Extract Gopher item listing'
  15105.  &END = PFK(END)
  15106.  &ZCMD = &Z
  15107.  VGET (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  15108.  &GGEXAPP = TRANS(&GGEXAPP Y,YES N,NO ' ',NO)
  15109.  &GGEXBLK = TRANS(&GGEXBLK Y,YES N,NO ' ',NO)
  15110. )PROC
  15111.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  15112.  VER(&GGEXDSN,NB,DSNAME)
  15113.  &GGEXAPP = TRUNC(&GGEXAPP,1)
  15114.  VER(&GGEXAPP,NB,LIST,Y,N)
  15115.  &GGEXBLK = TRUNC(&GGEXBLK,1)
  15116.  VER(&GGEXBLK,NB,LIST,Y,N)
  15117.  VPUT (GGEXDSN GGEXAPP GGEXBLK GGEXSEP) PROFILE
  15118. )END
  15119. ./ ADD NAME=GGMPEXOW
  15120. )ATTR
  15121. /*                                                                   /*
  15122. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15123. /*                                                                   /*
  15124. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15125. /* including the implied warranties of merchantability and fitness,  /*
  15126. /* are expressly denied.                                             /*
  15127. /*                                                                   /*
  15128. /* Provided this copyright notice is included, this software may     /*
  15129. /* be freely distributed and not offered for sale.                   /*
  15130. /*                                                                   /*
  15131. /* Changes or modifications may be made and used only by the maker   /*
  15132. /* of same, and not further distributed.  Such modifications should  /*
  15133. /* be mailed to the author for consideration for addition to the     /*
  15134. /* software and incorporation in subsequent releases.                /*
  15135. /*                                                                   /*
  15136.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15137. )BODY WINDOW(58,10)
  15138. +
  15139. %Command ===>^ZCMD
  15140. +
  15141. +Dataset already exists:
  15142. +
  15143. %&GGEXDSN
  15144. +
  15145. +Press%ENTER+to%&ACTION
  15146. +Press%&END (END)+to cancel the request.
  15147. +
  15148. )INIT
  15149.  .ALARM = YES
  15150.  &ZWINTTL = 'Extract To Existing Data Set'
  15151.  &END = PFK(END)
  15152.  &APP = TRUNC(&GGEXAPP,1)
  15153.  IF (&APP = Y) &ACTION = 'append to the end of the data set.'
  15154.  ELSE          &ACTION = 'overwrite the current data set.'
  15155. )PROC
  15156.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  15157. )END
  15158. ./ ADD NAME=GGMPEXPW
  15159. )ATTR
  15160. /*                                                                   /*
  15161. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15162. /*                                                                   /*
  15163. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15164. /* including the implied warranties of merchantability and fitness,  /*
  15165. /* are expressly denied.                                             /*
  15166. /*                                                                   /*
  15167. /* Provided this copyright notice is included, this software may     /*
  15168. /* be freely distributed and not offered for sale.                   /*
  15169. /*                                                                   /*
  15170. /* Changes or modifications may be made and used only by the maker   /*
  15171. /* of same, and not further distributed.  Such modifications should  /*
  15172. /* be mailed to the author for consideration for addition to the     /*
  15173. /* software and incorporation in subsequent releases.                /*
  15174. /*                                                                   /*
  15175.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15176. )BODY WINDOW(58,13)
  15177. +
  15178. %Command ===>^ZCMD
  15179. +
  15180. +Partitioned dataset already exists:
  15181. +
  15182. %&GGEXDSN
  15183. +
  15184. +If member names are generated that match existing members
  15185. +of this PDS, they will be%overwritten.+
  15186. +
  15187. +Press%ENTER+to proceed to use this PDS.
  15188. +Press%&END (END)+to cancel the request.
  15189. +
  15190. )INIT
  15191.  .ALARM = YES
  15192.  &ZWINTTL = 'Extract To Members of Existing PDS'
  15193.  &END = PFK(END)
  15194. )PROC
  15195.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  15196. )END
  15197. ./ ADD NAME=GGMPOPT
  15198. )ATTR
  15199. /*                                                                   /*
  15200. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15201. /*                                                                   /*
  15202. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15203. /* including the implied warranties of merchantability and fitness,  /*
  15204. /* are expressly denied.                                             /*
  15205. /*                                                                   /*
  15206. /* Provided this copyright notice is included, this software may     /*
  15207. /* be freely distributed and not offered for sale.                   /*
  15208. /*                                                                   /*
  15209. /* Changes or modifications may be made and used only by the maker   /*
  15210. /* of same, and not further distributed.  Such modifications should  /*
  15211. /* be mailed to the author for consideration for addition to the     /*
  15212. /* software and incorporation in subsequent releases.                /*
  15213. /*                                                                   /*
  15214.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15215. )BODY WINDOW(77,10)
  15216. +
  15217. %Command ===>^ZCMD
  15218. +
  15219. +Move cursor to choice (or type%S+next to choice) and press%ENTER+to select:
  15220. +
  15221. _Z%1+- Display viewing options
  15222. _Z%2+- Other options
  15223. +
  15224. +Press%&END (END)+to return to the previous panel.
  15225. )INIT
  15226.  .ZVARS = '(S1 S2)'
  15227.  .CURSOR = ZCMD
  15228.  &ZWINTTL = 'Customize user options'
  15229.  &END = PFK(END)
  15230.  &ZCMD = &Z
  15231.  &S1   = &Z
  15232.  &S2   = &Z
  15233. )PROC
  15234.  IF (&ZCMD ^= &Z)
  15235.   &GGCHOICE = TRANS(&ZCMD 1 1 2 2 * ?)
  15236.  ELSE
  15237.   &TEMP = '&S1/&S2'
  15238.   IF (&TEMP = '/')
  15239.    &GGCHOICE = TRANS(.CURSOR S1 1 S2 2 * ?)
  15240.   ELSE
  15241.    &GGCHOICE = TRANS(&TEMP  'S/' 1
  15242.                             '1/' 1
  15243.                             '/S' 2
  15244.                             '/2' 2
  15245.                                * ?
  15246.                    )
  15247. )END
  15248. ./ ADD NAME=GGMPPRDS
  15249. )ATTR
  15250. /*                                                                   /*
  15251. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     /*
  15252. /*                                                                   /*
  15253. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15254. /* including the implied warranties of merchantability and fitness,  /*
  15255. /* are expressly denied.                                             /*
  15256. /*                                                                   /*
  15257. /* Provided this copyright notice is included, this software may     /*
  15258. /* be freely distributed and not offered for sale.                   /*
  15259. /*                                                                   /*
  15260. /* Changes or modifications may be made and used only by the maker   /*
  15261. /* of same, and not further distributed.  Such modifications should  /*
  15262. /* be mailed to the author for consideration for addition to the     /*
  15263. /* software and incorporation in subsequent releases.                /*
  15264. /*                                                                   /*
  15265.  ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15266.  #   TYPE(TEXT)  INTENS(LOW)
  15267.  @   TYPE(INPUT) INTENS(HIGH) CAPS(ON)  JUST(LEFT)
  15268. )BODY WINDOW(77,12)
  15269. +
  15270. %Command ===>^ZCMD
  15271. +
  15272. %&SUBJECT
  15273. +
  15274. +SYSOUT class ===>_Z+   Number of copies ===>_Z  +
  15275. #Destination  ===>@Z       #  Forms ===>@Z   #   UCS ===>@Z   +
  15276.  
  15277. +(Note: Print data will be released to SYSOUT immediately.)
  15278.  
  15279.  
  15280. +Press%&END (END)+to cancel the print request.
  15281. )INIT
  15282.  .ZVARS = '(GGEXSCL GGEXSCO GGEXSDE GGEXSFO GGEXSUC)'
  15283.  .CURSOR = GGEXSCL
  15284.  &ZWINTTL = 'Print text'
  15285.  &SUBJECT = '&GGTSUBJ'
  15286.  &END = PFK(END)
  15287.  &ZCMD = &Z
  15288.  &GGEXSCO = 1
  15289.  &PVARS = 'GGEXSCL'
  15290.  IF (&GGALLPR ^= &Z)
  15291.   &PVARS = '&PVARS GGEXSDE GGEXSFO GGEXSUC'
  15292.   .ATTRCHAR('#') = 'TYPE(TEXT)   INTENS(LOW)'
  15293.   .ATTRCHAR('@') = 'TYPE(INPUT)  INTENS(HIGH) CAPS(ON)  JUST(LEFT)'
  15294.  ELSE
  15295.   .ATTRCHAR('#') = 'TYPE(TEXT)   INTENS(NON)'
  15296.   .ATTRCHAR('@') = 'TYPE(OUTPUT) INTENS(NON)'
  15297.  VGET (&PVARS) PROFILE
  15298. )PROC
  15299.  IF (&ZCMD ^= &Z) .MSG = ISPZ001
  15300.  VER(&GGEXSCL,NB)
  15301.  IF (&GGEXSCO = &Z) &GGEXSCO = 1
  15302.  VER(&GGEXSCO,NUM)
  15303.  VER(&GGEXSCO,RANGE,1,255)
  15304.  VPUT (&PVARS) PROFILE
  15305. )END
  15306. ./ ADD NAME=GGMPWAIS
  15307. )ATTR
  15308. /*                                                                   /*
  15309. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15310. /*                                                                   /*
  15311. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15312. /* including the implied warranties of merchantability and fitness,  /*
  15313. /* are expressly denied.                                             /*
  15314. /*                                                                   /*
  15315. /* Provided this copyright notice is included, this software may     /*
  15316. /* be freely distributed and not offered for sale.                   /*
  15317. /*                                                                   /*
  15318. /* Changes or modifications may be made and used only by the maker   /*
  15319. /* of same, and not further distributed.  Such modifications should  /*
  15320. /* be mailed to the author for consideration for addition to the     /*
  15321. /* software and incorporation in subsequent releases.                /*
  15322. /*                                                                   /*
  15323.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15324. )BODY WINDOW(58,10)
  15325. +
  15326. %Command ===>^ZCMD
  15327. +
  15328. +Enter index search query:
  15329. +
  15330. %===>^GGWAISQ
  15331.  
  15332. +Press%ENTER+to submit search request.
  15333. +Press%&END (END)+to cancel the request.
  15334. +
  15335. )INIT
  15336.  &ZWINTTL = 'GOPHER Full Text Index Search'
  15337.  &END = PFK(END)
  15338.  .CURSOR = GGWAISQ
  15339. )PROC
  15340.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  15341.  VER (&GGWAISQ,NB)
  15342.  VPUT (GGWAISQ) PROFILE
  15343. )END
  15344. ./ ADD NAME=GGMPWHOI
  15345. )ATTR
  15346. /*                                                                   /*
  15347. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1992     /*
  15348. /*                                                                   /*
  15349. /* This software is provided on an "AS IS" basis.  All warranties,   /*
  15350. /* including the implied warranties of merchantability and fitness,  /*
  15351. /* are expressly denied.                                             /*
  15352. /*                                                                   /*
  15353. /* Provided this copyright notice is included, this software may     /*
  15354. /* be freely distributed and not offered for sale.                   /*
  15355. /*                                                                   /*
  15356. /* Changes or modifications may be made and used only by the maker   /*
  15357. /* of same, and not further distributed.  Such modifications should  /*
  15358. /* be mailed to the author for consideration for addition to the     /*
  15359. /* software and incorporation in subsequent releases.                /*
  15360. /*                                                                   /*
  15361.        ^   TYPE(INPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15362. )BODY WINDOW(58,10)
  15363. +
  15364. %Command ===>^ZCMD
  15365. +
  15366. +Enter name to search for:
  15367. +
  15368. %===>^GGWHOISQ
  15369.  
  15370. +Press%ENTER+to submit search request.
  15371. +Press%&END (END)+to cancel the request.
  15372. +
  15373. )INIT
  15374.  &ZWINTTL = 'WHOIS/FINGER User Name Search'
  15375.  &END = PFK(END)
  15376.  .CURSOR = GGWHOISQ
  15377. )PROC
  15378.  IF  (&ZCMD ^= &Z) .MSG = ISPZ001
  15379.  VER (&GGWHOISQ,NB)
  15380.  VPUT (GGWHOISQ) PROFILE
  15381. )END
  15382. ./ ADD NAME=GGMVIEW
  15383. )ATTR DEFAULT(%+_)
  15384. /*                                                                   */
  15385. /* Copyright (c) The Charles Stark Draper Laboratory, Inc., 1993     */
  15386. /*                                                                   */
  15387. /* This software is provided on an "AS IS" basis.  All warranties,   */
  15388. /* including the implied warranties of merchantability and fitness,  */
  15389. /* are expressly denied.                                             */
  15390. /*                                                                   */
  15391. /* Provided this copyright notice is included, this software may     */
  15392. /* be freely distributed and not offered for sale.                   */
  15393. /*                                                                   */
  15394. /* Changes or modifications may be made and used only by the maker   */
  15395. /* of same, and not further distributed.  Such modifications should  */
  15396. /* be mailed to the author for consideration for addition to the     */
  15397. /* software and incorporation in subsequent releases.                */
  15398. /*                                                                   */
  15399.  ^  TYPE(INPUT)  INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15400.  #  TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(RIGHT)
  15401.  \  TYPE(OUTPUT) INTENS(HIGH) CAPS(OFF) JUST(LEFT)
  15402.  |  AREA(DYNAMIC) EXTEND(ON) SCROLL(ON) USERMOD(05)
  15403.  01 TYPE(DATAOUT) INTENS(LOW)
  15404.  02 TYPE(DATAOUT) INTENS(HIGH)
  15405.  03 TYPE(DATAIN)  INTENS(LOW)
  15406.  04 TYPE(DATAIN)  INTENS(HIGH)
  15407. )BODY
  15408. \GGBTITLE
  15409. %COMMAND ===>^ZCMD                                            %SCROLL ===>_Z   +
  15410. |GGBDYNA                                                                       |
  15411. )INIT
  15412.  .ZVARS = GGMBROSC
  15413.  IF (&GGMBROSC = &Z) &GGMBROSC = CSR
  15414.  .CURSOR = &GGBCUR
  15415.  .CSRPOS = &GGBPOS
  15416. )PROC
  15417.  &GGBCUR = .CURSOR
  15418.  &GGBPOS = .CSRPOS
  15419.  &GGBLVL = LVLINE(GGBDYNA)
  15420.  VPUT (GGMBROSC) PROFILE
  15421. )END
  15422. ./ ENDUP
  15423. ?!
  15424.